From e97f7b44377296dd6578548619de557dc5b1d107 Mon Sep 17 00:00:00 2001 From: Harun Wangereka Date: Thu, 5 Jun 2025 15:16:32 +0300 Subject: [PATCH 01/18] Migrating to kts --- android/build.gradle | 131 ------------------------- android/build.gradle.kts | 140 +++++++++++++++++++++++++++ example/android/app/build.gradle | 35 ------- example/android/app/build.gradle.kts | 35 +++++++ example/android/build.gradle | 30 ------ example/android/build.gradle.kts | 30 ++++++ 6 files changed, 205 insertions(+), 196 deletions(-) delete mode 100644 android/build.gradle create mode 100644 android/build.gradle.kts delete mode 100644 example/android/app/build.gradle create mode 100644 example/android/app/build.gradle.kts delete mode 100644 example/android/build.gradle create mode 100644 example/android/build.gradle.kts diff --git a/android/build.gradle b/android/build.gradle deleted file mode 100644 index 4f19606..0000000 --- a/android/build.gradle +++ /dev/null @@ -1,131 +0,0 @@ -def kotlinVersion = findProperty('kotlinVersion') ?: '2.1.0' -//def smileVersion = findProperty('smileVersion') ?: '11.0.1-SNAPSHOT' // Uncomment this line to use the latest snapshot version also uncomment the snapshot repository' -def smileVersion = findProperty('smileVersion') ?: '11.0.1' -def kotlinCompilerExtension = findProperty('kotlinCompilerExtensionVersion') ?: '1.5.14' - -ext { - project.ext.kotlinVersion = kotlinVersion - project.ext.smileVersion = smileVersion - project.ext.kotlinCompilerExtension = kotlinCompilerExtension -} - -buildscript { - def kotlinVersion = rootProject.findProperty('kotlinVersion') ?: '2.1.0' - - repositories { - google() - mavenCentral() - maven { url "https://plugins.gradle.org/m2/" } -// uncomment for development to test snapshots -// maven { -// url = 'https://central.sonatype.com/repository/maven-snapshots/' -// } - } - - dependencies { - classpath "com.android.tools.build:gradle:8.7.3" - if (kotlinVersion?.startsWith("2")) { - classpath "org.jetbrains.kotlin:compose-compiler-gradle-plugin:$kotlinVersion" - } else { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" - } - classpath "org.jlleitschuh.gradle:ktlint-gradle:12.2.0" - } -} - -allprojects { - repositories { - google() - mavenCentral() -// uncomment for development to test snapshots -// maven { -// url = 'https://central.sonatype.com/repository/maven-snapshots/' -// } - } -} - -apply plugin: "com.android.library" -apply plugin: "kotlin-android" -apply plugin: "org.jlleitschuh.gradle.ktlint" -if (kotlinVersion?.startsWith("2")) { - apply plugin: "org.jetbrains.kotlin.plugin.compose" -} - -android { - namespace 'com.smileidentity.flutter' - compileSdk 35 - - defaultConfig { - minSdk 21 - - // Read version from pubspec.yaml for setWrapperInfo - def pubspecYaml = new File("../pubspec.yaml") - def pubspecText = pubspecYaml.text - def versionLine = pubspecText.find(/version:\s*(.+)/) - def version = versionLine ? pubspecText.split(/version:\s*/)[1].split(/\n/)[0].trim() : "11.0.0" - buildConfigField "String", "SMILE_ID_VERSION", "\"${version}\"" - } - - buildFeatures { - buildConfig true - } - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - kotlinOptions { - jvmTarget = '17' - freeCompilerArgs += ['-Xskip-metadata-version-check'] // metadata version check skip flag - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - test.java.srcDirs += 'src/test/kotlin' - } - - lint { - disable "NullSafeMutableLiveData" - } - - testOptions { - unitTests.all { - useJUnitPlatform() - - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen { false } - showStandardStreams = true - } - } - } - - buildFeatures.compose = true - if (!kotlinVersion?.startsWith("2")) { - composeOptions { - kotlinCompilerExtensionVersion = kotlinCompilerExtension - } - } - - dependencies { - implementation "com.smileidentity:android-sdk:${smileVersion}" - implementation "androidx.core:core-ktx" - implementation "androidx.compose.ui:ui" - implementation 'androidx.lifecycle:lifecycle-viewmodel-compose' - implementation "androidx.compose.material3:material3" - implementation "androidx.fragment:fragment-ktx" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core" - implementation "org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8" - implementation "com.google.mlkit:object-detection:17.0.2" - - testImplementation "org.jetbrains.kotlin:kotlin-test" - testImplementation "io.mockk:mockk:1.13.13" - } -} - -ktlint { - android = true - filter { - exclude { it.file.path.contains(".g.kt") } - } -} diff --git a/android/build.gradle.kts b/android/build.gradle.kts new file mode 100644 index 0000000..3ca8919 --- /dev/null +++ b/android/build.gradle.kts @@ -0,0 +1,140 @@ +val kotlinVersion = findProperty("kotlinVersion") as String? ?: "2.1.0" +//val smileVersion = findProperty("smileVersion") as String? ?: "11.0.1-SNAPSHOT" // Uncomment this line to use the latest snapshot version also uncomment the snapshot repository +val smileVersion = findProperty("smileVersion") as String? ?: "11.0.1" +val kotlinCompilerExtension = findProperty("kotlinCompilerExtensionVersion") as String? ?: "1.5.14" + +extra.apply { + set("kotlinVersion", kotlinVersion) + set("smileVersion", smileVersion) + set("kotlinCompilerExtension", kotlinCompilerExtension) +} + +buildscript { + val kotlinVersionBuildScript = rootProject.findProperty("kotlinVersion") as String? ?: "2.1.0" + + repositories { + google() + mavenCentral() + maven { url = uri("https://plugins.gradle.org/m2/") } +// uncomment for development to test snapshots +// maven { +// url = uri("https://central.sonatype.com/repository/maven-snapshots/") +// } + } + + dependencies { + classpath("com.android.tools.build:gradle:8.7.3") + if (kotlinVersionBuildScript.startsWith("2")) { + classpath("org.jetbrains.kotlin:compose-compiler-gradle-plugin:$kotlinVersionBuildScript") + } else { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersionBuildScript") + } + classpath("org.jlleitschuh.gradle:ktlint-gradle:12.2.0") + } +} + +allprojects { + repositories { + google() + mavenCentral() +// uncomment for development to test snapshots +// maven { +// url = uri("https://central.sonatype.com/repository/maven-snapshots/") +// } + } +} + +plugins { + id("com.android.library") + id("kotlin-android") + id("org.jlleitschuh.gradle.ktlint") +} + +// Apply compose plugin conditionally for Kotlin 2.x +if (kotlinVersion.startsWith("2")) { + apply(plugin = "org.jetbrains.kotlin.plugin.compose") +} + +android { + namespace = "com.smileidentity.flutter" + compileSdk = 35 + + defaultConfig { + minSdk = 21 + + // Read version from pubspec.yaml for setWrapperInfo + val pubspecYaml = File("../pubspec.yaml") + val pubspecText = pubspecYaml.readText() + val versionRegex = Regex("""version:\s*(.+)""") + val versionMatch = versionRegex.find(pubspecText) + val version = if (versionMatch != null) { + pubspecText.split(Regex("""version:\s*"""))[1].split("\n")[0].trim() + } else { + "11.0.0" + } + buildConfigField("String", "SMILE_ID_VERSION", "\"$version\"") + } + + buildFeatures { + buildConfig = true + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = "17" + freeCompilerArgs += listOf("-Xskip-metadata-version-check") // metadata version check skip flag + } + + sourceSets { + getByName("main").java.srcDirs("src/main/kotlin") + getByName("test").java.srcDirs("src/test/kotlin") + } + + lint { + disable.add("NullSafeMutableLiveData") + } + + tasks.withType { + useJUnitPlatform() + + testLogging { + events("passed", "skipped", "failed", "standardOut", "standardError") + outputs.upToDateWhen { false } + showStandardStreams = true + } + } + + + buildFeatures.compose = true + if (!kotlinVersion.startsWith("2")) { + composeOptions { + kotlinCompilerExtensionVersion = kotlinCompilerExtension + } + } +} + +dependencies { + implementation("com.smileidentity:android-sdk:$smileVersion") + implementation("androidx.core:core-ktx") + implementation("androidx.compose.ui:ui") + implementation("androidx.lifecycle:lifecycle-viewmodel-compose") + implementation("androidx.compose.material3:material3") + implementation("androidx.fragment:fragment-ktx") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core") + implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8") + implementation("com.google.mlkit:object-detection:17.0.2") + + testImplementation("org.jetbrains.kotlin:kotlin-test") + testImplementation("io.mockk:mockk:1.13.13") +} + +ktlint { + android.set(true) + filter { + exclude { it.file.path.contains(".g.kt") } + } +} diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle deleted file mode 100644 index 778c194..0000000 --- a/example/android/app/build.gradle +++ /dev/null @@ -1,35 +0,0 @@ -plugins { - id "com.android.application" - id "kotlin-android" - id "org.jlleitschuh.gradle.ktlint" - id "dev.flutter.flutter-gradle-plugin" -} - -android { - namespace "com.smileidentity.flutter.sample" - compileSdk 35 - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - applicationId "com.smileidentity.flutter.sample" - minSdk 21 - targetSdkVersion flutter.targetSdkVersion - versionCode 1 - versionName "1.0.0" - } - - buildTypes { - release { - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } - - kotlinOptions { - jvmTarget = '17' - freeCompilerArgs += ['-Xskip-metadata-version-check'] - } -} \ No newline at end of file diff --git a/example/android/app/build.gradle.kts b/example/android/app/build.gradle.kts new file mode 100644 index 0000000..c3f4321 --- /dev/null +++ b/example/android/app/build.gradle.kts @@ -0,0 +1,35 @@ +plugins { + id("com.android.application") + id("kotlin-android") + id("org.jlleitschuh.gradle.ktlint") + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.smileidentity.flutter.sample" + compileSdk = 35 + + sourceSets { + getByName("main").java.srcDirs("src/main/kotlin") + } + + defaultConfig { + applicationId = "com.smileidentity.flutter.sample" + minSdk = 21 + targetSdk = flutter.targetSdkVersion + versionCode = 1 + versionName = "1.0.0" + } + + buildTypes { + getByName("release") { + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } + + kotlinOptions { + jvmTarget = "17" + freeCompilerArgs += listOf("-Xskip-metadata-version-check") + } +} diff --git a/example/android/build.gradle b/example/android/build.gradle deleted file mode 100644 index 4f77343..0000000 --- a/example/android/build.gradle +++ /dev/null @@ -1,30 +0,0 @@ -// set your desired versions here -//project.ext { -// kotlinVersion = "1.9.24" -// kotlinCompilerExtensionVersion = "1.5.14" -//} - -allprojects { - repositories { - google() - mavenCentral() -// uncomment for development to test snapshots -// maven { -// url = 'https://central.sonatype.com/repository/maven-snapshots/' -// } - } -} - -rootProject.buildDir = '../build' - -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} - -subprojects { - project.evaluationDependsOn(':app') -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} \ No newline at end of file diff --git a/example/android/build.gradle.kts b/example/android/build.gradle.kts new file mode 100644 index 0000000..dc9e684 --- /dev/null +++ b/example/android/build.gradle.kts @@ -0,0 +1,30 @@ +// set your desired versions here +//project.ext { +// kotlinVersion = "1.9.24" +// kotlinCompilerExtensionVersion = "1.5.14" +//} + +allprojects { + repositories { + google() + mavenCentral() +// uncomment for development to test snapshots +// maven { +// url = uri("https://central.sonatype.com/repository/maven-snapshots/") +// } + } +} + +rootProject.layout.buildDirectory.set(file("../build")) + +subprojects { + project.layout.buildDirectory.set(file("${rootProject.layout.buildDirectory.get()}/${project.name}")) +} + +subprojects { + project.evaluationDependsOn(":app") +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} From f98ace90957400c91fc53bb41d558aecb2a0d297 Mon Sep 17 00:00:00 2001 From: Harun Wangereka Date: Thu, 5 Jun 2025 17:14:20 +0300 Subject: [PATCH 02/18] Adding a shared versions file for example android project and the flutter android sdk --- android/gradle/libs.versions.toml | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 android/gradle/libs.versions.toml diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml new file mode 100644 index 0000000..e69de29 From 26b3ce9884f6293cb102f964b42cd0d63c0c30cc Mon Sep 17 00:00:00 2001 From: Harun Wangereka Date: Thu, 5 Jun 2025 22:57:15 +0300 Subject: [PATCH 03/18] Migrating dependencies logic to libs.versions.toml file --- android/build.gradle.kts | 7 +++---- android/gradle/libs.versions.toml | 32 +++++++++++++++++++++++++++++ android/settings.gradle | 1 - android/settings.gradle.kts | 1 + example/android/build.gradle.kts | 27 ++++++++++++++++-------- example/android/settings.gradle | 26 ----------------------- example/android/settings.gradle.kts | 31 ++++++++++++++++++++++++++++ 7 files changed, 85 insertions(+), 40 deletions(-) delete mode 100644 android/settings.gradle create mode 100644 android/settings.gradle.kts delete mode 100644 example/android/settings.gradle create mode 100644 example/android/settings.gradle.kts diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 3ca8919..c12729a 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -29,7 +29,6 @@ buildscript { } else { classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersionBuildScript") } - classpath("org.jlleitschuh.gradle:ktlint-gradle:12.2.0") } } @@ -45,9 +44,9 @@ allprojects { } plugins { - id("com.android.library") - id("kotlin-android") - id("org.jlleitschuh.gradle.ktlint") + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.ktlint) } // Apply compose plugin conditionally for Kotlin 2.x diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index e69de29..94ba266 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -0,0 +1,32 @@ +[versions] +android-gradle-plugin = "8.7.3" +flutter-plugin-loader = "1.0.0" +kotlin = "2.1.0" +kotlin-immutable-collections = "0.4.0" +ktlint-plugin = "12.1.3" +mockk = "1.13.13" +mlkit = "17.0.2" +smile-id = "11.0.1" +smile-id-snapshot = "11.0.1-SNAPSHOT" + +[libraries] +androidx-core-ktx = { module = "androidx.core:core-ktx" } +androidx-compose-ui = { module = "androidx.compose.ui:ui" } +androidx-compose-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-compose" } +androidx-compose-material3 = { module = "androidx.compose.material3:material3" } +androidx-fragment = { module = "androidx.fragment:fragment-ktx" } +koltin-coroutines = { module ="org.jetbrains.kotlinx:kotlinx-coroutines-core" } +kotlin-immutable-collections = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlin-immutable-collections" } +kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test" } +mockk = { module = "io.mockk:mockk", version.ref = "mockk" } +smile-id = { module = "com.smileidentity:smile-id", version.ref = "smile-id" } +smile-id-snapshot = { module = "com.smileidentity:smile-id", version.ref = "smile-id-snapshot" } + + +[plugins] +android-application = { id = "com.android.application", version.ref = "android-gradle-plugin" } +android-library = { id = "com.android.library", version.ref = "android-gradle-plugin" } +flutter-plugin-loader = { id = "dev.flutter.flutter-plugin-loader", version.ref = "flutter-plugin-loader" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint-plugin" } \ No newline at end of file diff --git a/android/settings.gradle b/android/settings.gradle deleted file mode 100644 index 5213145..0000000 --- a/android/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = 'smile_id_flutter' diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts new file mode 100644 index 0000000..d350ccf --- /dev/null +++ b/android/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "smile_id_flutter" diff --git a/example/android/build.gradle.kts b/example/android/build.gradle.kts index dc9e684..2951df6 100644 --- a/example/android/build.gradle.kts +++ b/example/android/build.gradle.kts @@ -4,17 +4,24 @@ // kotlinCompilerExtensionVersion = "1.5.14" //} -allprojects { - repositories { - google() - mavenCentral() -// uncomment for development to test snapshots -// maven { -// url = uri("https://central.sonatype.com/repository/maven-snapshots/") -// } - } +plugins { + alias(libs.plugins.flutter.plugin.loader) + alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.ktlint) apply false } +//allprojects { +// repositories { +// google() +// mavenCentral() +//// uncomment for development to test snapshots +//// maven { +//// url = uri("https://central.sonatype.com/repository/maven-snapshots/") +//// } +// } +//} + rootProject.layout.buildDirectory.set(file("../build")) subprojects { @@ -28,3 +35,5 @@ subprojects { tasks.register("clean") { delete(rootProject.layout.buildDirectory) } + +// this diff --git a/example/android/settings.gradle b/example/android/settings.gradle deleted file mode 100644 index a2c3227..0000000 --- a/example/android/settings.gradle +++ /dev/null @@ -1,26 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - }() - - includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.7.3" apply false - id "org.jetbrains.kotlin.android" version "2.1.0" apply false - id "org.jlleitschuh.gradle.ktlint" version "12.1.2" apply false -} - -include ":app" \ No newline at end of file diff --git a/example/android/settings.gradle.kts b/example/android/settings.gradle.kts new file mode 100644 index 0000000..057d839 --- /dev/null +++ b/example/android/settings.gradle.kts @@ -0,0 +1,31 @@ +pluginManagement { + val flutterSdkPath = run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + requireNotNull(flutterSdkPath) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } + versionCatalogs { + create("libs") { + from(files("../../android/gradle/libs.versions.toml")) + } + } +} +include(":app") From 3073fa5643ccc44a9d4c83fd80bdcf984dc5f83a Mon Sep 17 00:00:00 2001 From: Harun Wangereka Date: Sun, 8 Jun 2025 22:40:57 +0300 Subject: [PATCH 04/18] Migrating dependencies logic to libs.versions.toml file --- android/build.gradle.kts | 1 - example/android/app/build.gradle.kts | 8 ++++---- example/android/settings.gradle.kts | 10 +++++----- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/android/build.gradle.kts b/android/build.gradle.kts index c12729a..2fd6adf 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -23,7 +23,6 @@ buildscript { } dependencies { - classpath("com.android.tools.build:gradle:8.7.3") if (kotlinVersionBuildScript.startsWith("2")) { classpath("org.jetbrains.kotlin:compose-compiler-gradle-plugin:$kotlinVersionBuildScript") } else { diff --git a/example/android/app/build.gradle.kts b/example/android/app/build.gradle.kts index c3f4321..65908ba 100644 --- a/example/android/app/build.gradle.kts +++ b/example/android/app/build.gradle.kts @@ -1,8 +1,8 @@ plugins { - id("com.android.application") - id("kotlin-android") - id("org.jlleitschuh.gradle.ktlint") - id("dev.flutter.flutter-gradle-plugin") + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.ktlint) + alias(libs.plugins.ktlint) } android { diff --git a/example/android/settings.gradle.kts b/example/android/settings.gradle.kts index 057d839..9e69202 100644 --- a/example/android/settings.gradle.kts +++ b/example/android/settings.gradle.kts @@ -17,15 +17,15 @@ pluginManagement { } dependencyResolutionManagement { - repositories { - google() - mavenCentral() - gradlePluginPortal() - } versionCatalogs { create("libs") { from(files("../../android/gradle/libs.versions.toml")) } } + repositories { + google() + mavenCentral() + gradlePluginPortal() + } } include(":app") From e3b220052d699b3c9b72880ce9f02f9036345102 Mon Sep 17 00:00:00 2001 From: Harun Wangereka Date: Mon, 9 Jun 2025 14:47:12 +0300 Subject: [PATCH 05/18] Migrating dependencies logic to libs.versions.toml file --- android/build.gradle.kts | 134 +- android/settings.gradle.kts | 20 + android/src/main/AndroidManifest.xml | 1 - .../com/smileidentity/flutter/Mapper.kt | 601 ---- .../flutter/SmileComposablePlatformView.kt | 112 - .../flutter/SmileIDBiometricKYC.kt | 111 - .../flutter/SmileIDDocumentCaptureView.kt | 153 - .../flutter/SmileIDDocumentVerification.kt | 96 - .../SmileIDEnhancedDocumentVerification.kt | 105 - .../smileidentity/flutter/SmileIDPlugin.kt | 470 --- .../SmileIDSmartSelfieAuthentication.kt | 51 - .../flutter/SmileIDSmartSelfieCaptureView.kt | 197 -- .../flutter/SmileIDSmartSelfieEnrollment.kt | 51 - .../SmileSelfieComposablePlatformView.kt | 49 - ...mileIDSmartSelfieAuthenticationEnhanced.kt | 51 - .../SmileIDSmartSelfieEnrollmentEnhanced.kt | 51 - .../flutter/generated/SmileIDMessages.g.kt | 2864 ----------------- .../flutter/results/DocumentCaptureResult.kt | 12 - .../results/SmartSelfieCaptureResult.kt | 10 - .../utils/DocumentCaptureResultAdapter.kt | 102 - .../utils/SelfieCaptureResultAdapter.kt | 93 - .../flutter/utils/SmileIDUtils.kt | 16 - .../flutter/SmileIDPluginTest.kt | 77 - example/android/app/build.gradle.kts | 19 +- .../android/app/src/main/AndroidManifest.xml | 1 - example/android/build.gradle.kts | 21 +- example/android/settings.gradle.kts | 13 +- 27 files changed, 52 insertions(+), 5429 deletions(-) delete mode 100644 android/src/main/AndroidManifest.xml delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/Mapper.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/SmileComposablePlatformView.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/SmileIDBiometricKYC.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentCaptureView.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentVerification.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/SmileIDEnhancedDocumentVerification.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieAuthentication.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieCaptureView.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieEnrollment.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/SmileSelfieComposablePlatformView.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieAuthenticationEnhanced.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieEnrollmentEnhanced.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/generated/SmileIDMessages.g.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/results/DocumentCaptureResult.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/results/SmartSelfieCaptureResult.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/utils/DocumentCaptureResultAdapter.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/utils/SelfieCaptureResultAdapter.kt delete mode 100644 android/src/main/kotlin/com/smileidentity/flutter/utils/SmileIDUtils.kt delete mode 100644 android/src/test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 2fd6adf..7591c92 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -1,133 +1,15 @@ -val kotlinVersion = findProperty("kotlinVersion") as String? ?: "2.1.0" -//val smileVersion = findProperty("smileVersion") as String? ?: "11.0.1-SNAPSHOT" // Uncomment this line to use the latest snapshot version also uncomment the snapshot repository -val smileVersion = findProperty("smileVersion") as String? ?: "11.0.1" -val kotlinCompilerExtension = findProperty("kotlinCompilerExtensionVersion") as String? ?: "1.5.14" - -extra.apply { - set("kotlinVersion", kotlinVersion) - set("smileVersion", smileVersion) - set("kotlinCompilerExtension", kotlinCompilerExtension) -} - -buildscript { - val kotlinVersionBuildScript = rootProject.findProperty("kotlinVersion") as String? ?: "2.1.0" - - repositories { - google() - mavenCentral() - maven { url = uri("https://plugins.gradle.org/m2/") } -// uncomment for development to test snapshots -// maven { -// url = uri("https://central.sonatype.com/repository/maven-snapshots/") -// } - } - - dependencies { - if (kotlinVersionBuildScript.startsWith("2")) { - classpath("org.jetbrains.kotlin:compose-compiler-gradle-plugin:$kotlinVersionBuildScript") - } else { - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersionBuildScript") - } - } -} - -allprojects { - repositories { - google() - mavenCentral() -// uncomment for development to test snapshots -// maven { -// url = uri("https://central.sonatype.com/repository/maven-snapshots/") -// } - } -} - plugins { - alias(libs.plugins.android.library) - alias(libs.plugins.kotlin.android) + // Applied to all sub-modules alias(libs.plugins.ktlint) -} - -// Apply compose plugin conditionally for Kotlin 2.x -if (kotlinVersion.startsWith("2")) { - apply(plugin = "org.jetbrains.kotlin.plugin.compose") -} - -android { - namespace = "com.smileidentity.flutter" - compileSdk = 35 - - defaultConfig { - minSdk = 21 - - // Read version from pubspec.yaml for setWrapperInfo - val pubspecYaml = File("../pubspec.yaml") - val pubspecText = pubspecYaml.readText() - val versionRegex = Regex("""version:\s*(.+)""") - val versionMatch = versionRegex.find(pubspecText) - val version = if (versionMatch != null) { - pubspecText.split(Regex("""version:\s*"""))[1].split("\n")[0].trim() - } else { - "11.0.0" - } - buildConfigField("String", "SMILE_ID_VERSION", "\"$version\"") - } - - buildFeatures { - buildConfig = true - } - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - - kotlinOptions { - jvmTarget = "17" - freeCompilerArgs += listOf("-Xskip-metadata-version-check") // metadata version check skip flag - } - - sourceSets { - getByName("main").java.srcDirs("src/main/kotlin") - getByName("test").java.srcDirs("src/test/kotlin") - } - lint { - disable.add("NullSafeMutableLiveData") - } - - tasks.withType { - useJUnitPlatform() - - testLogging { - events("passed", "skipped", "failed", "standardOut", "standardError") - outputs.upToDateWhen { false } - showStandardStreams = true - } - } - - - buildFeatures.compose = true - if (!kotlinVersion.startsWith("2")) { - composeOptions { - kotlinCompilerExtensionVersion = kotlinCompilerExtension - } - } + // Applied depending on sub-module + alias(libs.plugins.android.library) apply false + alias(libs.plugins.compose.compiler) apply false + alias(libs.plugins.kotlin.android) apply false } -dependencies { - implementation("com.smileidentity:android-sdk:$smileVersion") - implementation("androidx.core:core-ktx") - implementation("androidx.compose.ui:ui") - implementation("androidx.lifecycle:lifecycle-viewmodel-compose") - implementation("androidx.compose.material3:material3") - implementation("androidx.fragment:fragment-ktx") - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core") - implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8") - implementation("com.google.mlkit:object-detection:17.0.2") - - testImplementation("org.jetbrains.kotlin:kotlin-test") - testImplementation("io.mockk:mockk:1.13.13") +tasks.create("clean", Delete::class.java) { + delete(rootProject.layout.buildDirectory) } ktlint { @@ -135,4 +17,4 @@ ktlint { filter { exclude { it.file.path.contains(".g.kt") } } -} +} \ No newline at end of file diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index d350ccf..8570d07 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -1 +1,21 @@ rootProject.name = "smile_id_flutter" + +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositories { + google() + mavenCentral() + maven { + url = uri("https://central.sonatype.com/repository/maven-snapshots/") + } + } +} + +include(":lib") diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml deleted file mode 100644 index cc947c5..0000000 --- a/android/src/main/AndroidManifest.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/android/src/main/kotlin/com/smileidentity/flutter/Mapper.kt b/android/src/main/kotlin/com/smileidentity/flutter/Mapper.kt deleted file mode 100644 index 35e897f..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/Mapper.kt +++ /dev/null @@ -1,601 +0,0 @@ -package com.smileidentity.flutter - -import FlutterActionResult -import FlutterActions -import FlutterAntifraud -import FlutterAuthenticationRequest -import FlutterAuthenticationResponse -import FlutterAvailableIdType -import FlutterBankCode -import FlutterBiometricKycJobResult -import FlutterBiometricKycJobStatusResponse -import FlutterConfig -import FlutterConsentInfo -import FlutterConsentInformation -import FlutterCountry -import FlutterCountryInfo -import FlutterDocumentVerificationJobResult -import FlutterDocumentVerificationJobStatusResponse -import FlutterEnhancedDocumentVerificationJobResult -import FlutterEnhancedDocumentVerificationJobStatusResponse -import FlutterEnhancedKycAsyncResponse -import FlutterEnhancedKycRequest -import FlutterEnhancedKycResponse -import FlutterHostedWeb -import FlutterIdInfo -import FlutterIdSelection -import FlutterIdType -import FlutterImageLinks -import FlutterImageType -import FlutterJobStatusRequest -import FlutterJobType -import FlutterJobTypeV2 -import FlutterPartnerParams -import FlutterPrepUploadRequest -import FlutterPrepUploadResponse -import FlutterProductsConfigRequest -import FlutterProductsConfigResponse -import FlutterServicesResponse -import FlutterSmartSelfieJobResult -import FlutterSmartSelfieJobStatusResponse -import FlutterSmartSelfieResponse -import FlutterSmartSelfieStatus -import FlutterSuspectUser -import FlutterUploadImageInfo -import FlutterUploadRequest -import FlutterValidDocument -import FlutterValidDocumentsResponse -import com.smileidentity.flutter.utils.getCurrentIsoTimestamp -import com.smileidentity.models.ActionResult -import com.smileidentity.models.Actions -import com.smileidentity.models.Antifraud -import com.smileidentity.models.AuthenticationRequest -import com.smileidentity.models.AuthenticationResponse -import com.smileidentity.models.AvailableIdType -import com.smileidentity.models.BankCode -import com.smileidentity.models.BiometricKycJobResult -import com.smileidentity.models.BiometricKycJobStatusResponse -import com.smileidentity.models.Config -import com.smileidentity.models.ConsentInfo -import com.smileidentity.models.ConsentInformation -import com.smileidentity.models.ConsentedInformation -import com.smileidentity.models.Country -import com.smileidentity.models.CountryInfo -import com.smileidentity.models.DocumentVerificationJobResult -import com.smileidentity.models.DocumentVerificationJobStatusResponse -import com.smileidentity.models.EnhancedDocumentVerificationJobResult -import com.smileidentity.models.EnhancedDocumentVerificationJobStatusResponse -import com.smileidentity.models.EnhancedKycAsyncResponse -import com.smileidentity.models.EnhancedKycRequest -import com.smileidentity.models.EnhancedKycResponse -import com.smileidentity.models.HostedWeb -import com.smileidentity.models.IdInfo -import com.smileidentity.models.IdSelection -import com.smileidentity.models.IdType -import com.smileidentity.models.ImageLinks -import com.smileidentity.models.ImageType -import com.smileidentity.models.JobResult -import com.smileidentity.models.JobStatusRequest -import com.smileidentity.models.JobType -import com.smileidentity.models.PartnerParams -import com.smileidentity.models.PrepUploadRequest -import com.smileidentity.models.PrepUploadResponse -import com.smileidentity.models.ProductsConfigRequest -import com.smileidentity.models.ProductsConfigResponse -import com.smileidentity.models.ServicesResponse -import com.smileidentity.models.SmartSelfieJobResult -import com.smileidentity.models.SmartSelfieJobStatusResponse -import com.smileidentity.models.SuspectUser -import com.smileidentity.models.UploadImageInfo -import com.smileidentity.models.UploadRequest -import com.smileidentity.models.ValidDocument -import com.smileidentity.models.ValidDocumentsResponse -import com.smileidentity.models.v2.JobType as JobTypeV2 -import com.smileidentity.models.v2.SmartSelfieResponse -import com.smileidentity.models.v2.SmartSelfieStatus -import java.io.File - -/** - * Pigeon does not allow non nullable types in this example here - * - * final Map extras; - * - * Error: pigeons/messages.dart:18: Generic type arguments must be nullable in field "extras" in - * class "FlutterPartnerParams". - * - * The fix is these two helper functions to convert maps to nullable types, and vice versa - */ -fun convertNullableMapToNonNull(map: Map?): Map = map - ?.filterKeys { it != null } - ?.filterValues { it != null } - ?.mapKeys { it.key!! } - ?.mapValues { it.value!! } ?: mapOf() - -fun convertNonNullMapToNullable(map: Map): Map = map - .mapKeys { it.key } - .mapValues { it.value } - -fun FlutterJobType.toRequest() = when (this) { - FlutterJobType.ENHANCEDKYC -> JobType.EnhancedKyc - FlutterJobType.DOCUMENTVERIFICATION -> JobType.DocumentVerification - FlutterJobType.BIOMETRICKYC -> JobType.BiometricKyc - FlutterJobType.ENHANCEDDOCUMENTVERIFICATION -> JobType.EnhancedDocumentVerification - FlutterJobType.SMARTSELFIEENROLLMENT -> JobType.SmartSelfieEnrollment - FlutterJobType.SMARTSELFIEAUTHENTICATION -> JobType.SmartSelfieAuthentication -} - -fun JobType.toResponse() = when (this) { - JobType.EnhancedKyc -> FlutterJobType.ENHANCEDKYC - JobType.DocumentVerification -> FlutterJobType.DOCUMENTVERIFICATION - JobType.BiometricKyc -> FlutterJobType.BIOMETRICKYC - JobType.EnhancedDocumentVerification -> FlutterJobType.ENHANCEDDOCUMENTVERIFICATION - JobType.SmartSelfieEnrollment -> FlutterJobType.SMARTSELFIEENROLLMENT - JobType.SmartSelfieAuthentication -> FlutterJobType.SMARTSELFIEAUTHENTICATION - else -> TODO("Not yet implemented") -} - -fun FlutterJobTypeV2.toRequest() = when (this) { - FlutterJobTypeV2.SMARTSELFIEAUTHENTICATION -> JobTypeV2.SmartSelfieAuthentication - FlutterJobTypeV2.SMARTSELFIEENROLLMENT -> JobTypeV2.SmartSelfieEnrollment -} - -fun JobTypeV2.toResponse() = when (this) { - JobTypeV2.SmartSelfieAuthentication -> FlutterJobTypeV2.SMARTSELFIEAUTHENTICATION - JobTypeV2.SmartSelfieEnrollment -> FlutterJobTypeV2.SMARTSELFIEENROLLMENT - else -> TODO("Not yet implemented") -} - -fun FlutterAuthenticationRequest.toRequest() = AuthenticationRequest( - jobType = jobType.toRequest(), - country = country, - idType = idType, - updateEnrolledImage = updateEnrolledImage, - jobId = jobId, - userId = userId, -) - -fun PartnerParams.toResponse() = FlutterPartnerParams( - jobType = jobType?.toResponse(), - jobId = jobId, - userId = userId, - extras = convertNonNullMapToNullable(extras), -) - -fun FlutterPartnerParams.toRequest() = PartnerParams( - jobType = jobType?.toRequest(), - jobId = jobId, - userId = userId, - extras = convertNullableMapToNonNull(extras), -) - -fun ConsentInfo.toRequest() = FlutterConsentInfo( - canAccess = canAccess, - consentRequired = consentRequired, -) - -fun AuthenticationResponse.toResponse() = FlutterAuthenticationResponse( - success = success, - signature = signature, - timestamp = timestamp, - partnerParams = partnerParams.toResponse(), - callbackUrl = callbackUrl, - consentInfo = consentInfo?.toRequest(), -) - -fun FlutterPrepUploadRequest.toRequest() = PrepUploadRequest( - partnerParams = partnerParams.toRequest(), - callbackUrl = callbackUrl, - allowNewEnroll = allowNewEnroll, - partnerId = partnerId, - sourceSdk = "android (flutter)", - timestamp = timestamp, - signature = signature, -) - -fun PrepUploadResponse.toResponse() = FlutterPrepUploadResponse( - code = code, - refId = refId, - uploadUrl = uploadUrl, - smileJobId = smileJobId, -) - -fun FlutterUploadRequest.toRequest() = UploadRequest( - images = images.mapNotNull { it?.toRequest() }, - idInfo = idInfo?.toRequest(), -) - -fun FlutterUploadImageInfo.toRequest() = UploadImageInfo( - imageTypeId = imageTypeId.toRequest(), - image = File(imageName), -) - -fun FlutterImageType.toRequest() = when (this) { - FlutterImageType.SELFIEJPGFILE -> ImageType.SelfieJpgFile - FlutterImageType.IDCARDJPGFILE -> ImageType.IdCardJpgFile - FlutterImageType.SELFIEJPGBASE64 -> ImageType.SelfieJpgBase64 - FlutterImageType.IDCARDJPGBASE64 -> ImageType.IdCardJpgBase64 - FlutterImageType.LIVENESSJPGFILE -> ImageType.LivenessJpgFile - FlutterImageType.IDCARDREARJPGFILE -> ImageType.IdCardRearJpgFile - FlutterImageType.LIVENESSJPGBASE64 -> ImageType.LivenessJpgBase64 - FlutterImageType.IDCARDREARJPGBASE64 -> ImageType.IdCardRearJpgBase64 -} - -fun FlutterIdInfo.toRequest() = IdInfo( - country = country, - idType = idType, - idNumber = idNumber, - firstName = firstName, - middleName = middleName, - lastName = lastName, - dob = dob, - bankCode = bankCode, - entered = entered, -) - -fun FlutterConsentInformation.toRequest() = ConsentInformation( - consented = ConsentedInformation( - consentGrantedDate = consentGrantedDate, - personalDetails = personalDetailsConsentGranted, - contactInformation = contactInfoConsentGranted, - documentInformation = documentInfoConsentGranted, - ), -) - -fun FlutterEnhancedKycRequest.toRequest() = EnhancedKycRequest( - country = country, - idType = idType, - idNumber = idNumber, - firstName = firstName, - middleName = middleName, - lastName = lastName, - dob = dob, - phoneNumber = phoneNumber, - bankCode = bankCode, - callbackUrl = callbackUrl, - partnerParams = partnerParams.toRequest(), - sourceSdk = "android (flutter)", - timestamp = timestamp, - signature = signature, - consentInformation = - consentInformation?.toRequest() ?: ConsentInformation( - consented = ConsentedInformation( - consentGrantedDate = getCurrentIsoTimestamp(), - personalDetails = false, - contactInformation = false, - documentInformation = false, - ), - ), -) - -fun EnhancedKycResponse.toResponse() = FlutterEnhancedKycResponse( - smileJobId = smileJobId, - partnerParams = partnerParams.toResponse(), - resultText = resultText, - resultCode = resultCode, - actions = actions.toResponse(), - country = country, - idType = idType, - idNumber = idNumber, - fullName = fullName, - expirationDate = expirationDate, - dob = dob, - base64Photo = base64Photo, -) - -fun EnhancedKycAsyncResponse.toResponse() = FlutterEnhancedKycAsyncResponse( - success = success, -) - -fun Actions.toResponse() = FlutterActions( - documentCheck = documentCheck.toResponse(), - humanReviewCompare = humanReviewCompare.toResponse(), - humanReviewDocumentCheck = humanReviewDocumentCheck.toResponse(), - humanReviewLivenessCheck = humanReviewLivenessCheck.toResponse(), - humanReviewSelfieCheck = humanReviewSelfieCheck.toResponse(), - humanReviewUpdateSelfie = humanReviewUpdateSelfie.toResponse(), - livenessCheck = livenessCheck.toResponse(), - registerSelfie = registerSelfie.toResponse(), - returnPersonalInfo = returnPersonalInfo.toResponse(), - selfieCheck = selfieCheck.toResponse(), - selfieProvided = selfieProvided.toResponse(), - selfieToIdAuthorityCompare = selfieToIdAuthorityCompare.toResponse(), - selfieToIdCardCompare = selfieToIdCardCompare.toResponse(), - selfieToRegisteredSelfieCompare = selfieToRegisteredSelfieCompare.toResponse(), - updateRegisteredSelfieOnFile = updateRegisteredSelfieOnFile.toResponse(), - verifyDocument = verifyDocument.toResponse(), - verifyIdNumber = verifyIdNumber.toResponse(), -) - -fun ActionResult.toResponse() = when (this) { - ActionResult.Passed -> FlutterActionResult.PASSED - ActionResult.Completed -> FlutterActionResult.COMPLETED - ActionResult.Approved -> FlutterActionResult.APPROVED - ActionResult.Verified -> FlutterActionResult.VERIFIED - ActionResult.ProvisionallyApproved -> FlutterActionResult.PROVISIONALLYAPPROVED - ActionResult.Returned -> FlutterActionResult.RETURNED - ActionResult.NotReturned -> FlutterActionResult.NOTRETURNED - ActionResult.Failed -> FlutterActionResult.FAILED - ActionResult.Rejected -> FlutterActionResult.REJECTED - ActionResult.UnderReview -> FlutterActionResult.UNDERREVIEW - ActionResult.UnableToDetermine -> FlutterActionResult.UNABLETODETERMINE - ActionResult.NotApplicable -> FlutterActionResult.NOTAPPLICABLE - ActionResult.NotVerified -> FlutterActionResult.NOTVERIFIED - ActionResult.NotDone -> FlutterActionResult.NOTDONE - ActionResult.IssuerUnavailable -> FlutterActionResult.ISSUERUNAVAILABLE - ActionResult.IdAuthorityPhotoNotAvailable -> - FlutterActionResult.IDAUTHORITYPHOTONOTAVAILABLE - - ActionResult.SentToHumanReview -> FlutterActionResult.SENTTOHUMANREVIEW - ActionResult.Unknown -> FlutterActionResult.UNKNOWN -} - -fun ImageLinks.toResponse() = FlutterImageLinks( - selfieImageUrl = selfieImageUrl, - error = error, -) - -fun Antifraud.toResponse() = FlutterAntifraud( - suspectUsers = suspectUsers.map { it.toResponse() }, -) - -fun SuspectUser.toResponse() = FlutterSuspectUser( - reason = reason, - userId = userId, -) - -fun FlutterJobStatusRequest.toRequest() = JobStatusRequest( - userId = userId, - jobId = jobId, - includeImageLinks = includeImageLinks, - includeHistory = includeHistory, - partnerId = partnerId, - timestamp = timestamp, - signature = signature, -) - -fun SmartSelfieJobStatusResponse.toResponse() = FlutterSmartSelfieJobStatusResponse( - timestamp = timestamp, - jobComplete = jobComplete, - jobSuccess = jobSuccess, - code = code, - result = result?.toResponse() as? FlutterSmartSelfieJobResult, - resultString = result?.toResponse() as? String, - imageLinks = imageLinks?.toResponse(), -) - -fun SmartSelfieJobResult.toResponse(): Any = when (this) { - is JobResult.Freeform -> this.result - is SmartSelfieJobResult.Entry -> - FlutterSmartSelfieJobResult( - actions = actions.toResponse(), - resultCode = resultCode, - resultText = resultText, - smileJobId = smileJobId, - partnerParams = partnerParams.toResponse(), - confidence = confidence, - ) -} - -fun SmartSelfieStatus.toResponse() = when (this) { - SmartSelfieStatus.Approved -> FlutterSmartSelfieStatus.APPROVED - SmartSelfieStatus.Pending -> FlutterSmartSelfieStatus.PENDING - SmartSelfieStatus.Rejected -> FlutterSmartSelfieStatus.REJECTED - SmartSelfieStatus.Unknown -> FlutterSmartSelfieStatus.UNKNOWN -} - -fun SmartSelfieResponse.toResponse() = FlutterSmartSelfieResponse( - code = code, - createdAt = createdAt, - jobId = jobId, - jobType = jobType.toResponse(), - message = message, - partnerId = partnerId, - partnerParams = convertNonNullMapToNullable(partnerParams), - status = status.toResponse(), - updatedAt = updatedAt, - userId = userId, -) - -fun DocumentVerificationJobStatusResponse.toResponse() = - FlutterDocumentVerificationJobStatusResponse( - timestamp = timestamp, - jobComplete = jobComplete, - jobSuccess = jobSuccess, - code = code, - result = result?.toResponse() as? FlutterDocumentVerificationJobResult, - resultString = result?.toResponse() as? String, - imageLinks = imageLinks?.toResponse(), - ) - -fun DocumentVerificationJobResult.toResponse(): Any = when (this) { - is JobResult.Freeform -> this.result - is DocumentVerificationJobResult.Entry -> - FlutterDocumentVerificationJobResult( - actions = actions.toResponse(), - resultCode = resultCode, - resultText = resultText, - smileJobId = smileJobId, - partnerParams = partnerParams.toResponse(), - country = country, - idType = idType, - fullName = fullName, - idNumber = idNumber, - dob = dob, - gender = gender, - expirationDate = expirationDate, - documentImageBase64 = documentImageBase64, - phoneNumber = phoneNumber, - phoneNumber2 = phoneNumber2, - address = address, - ) -} - -fun BiometricKycJobStatusResponse.toResponse() = FlutterBiometricKycJobStatusResponse( - timestamp = timestamp, - jobComplete = jobComplete, - jobSuccess = jobSuccess, - code = code, - result = result?.toResponse() as? FlutterBiometricKycJobResult, - resultString = result?.toResponse() as? String, - imageLinks = imageLinks?.toResponse(), -) - -fun BiometricKycJobResult.toResponse(): Any = when (this) { - is JobResult.Freeform -> this.result - is BiometricKycJobResult.Entry -> - FlutterBiometricKycJobResult( - actions = actions.toResponse(), - resultCode = resultCode, - resultText = resultText, - resultType = resultType, - smileJobId = smileJobId, - partnerParams = partnerParams.toResponse(), - antifraud = antifraud?.toResponse(), - dob = dob, - photoBase64 = photoBase64, - gender = gender, - idType = idType, - address = address, - country = country, - documentImageBase64 = documentImageBase64, - fullData = fullData?.mapKeys { it.key }?.mapValues { it.value.toString() }, - fullName = fullName, - idNumber = idNumber, - phoneNumber = phoneNumber, - phoneNumber2 = phoneNumber2, - expirationDate = expirationDate, - ) -} - -fun EnhancedDocumentVerificationJobStatusResponse.toResponse() = - FlutterEnhancedDocumentVerificationJobStatusResponse( - timestamp = timestamp, - jobComplete = jobComplete, - jobSuccess = jobSuccess, - code = code, - result = result?.toResponse() as? FlutterEnhancedDocumentVerificationJobResult, - resultString = result?.toResponse() as? String, - imageLinks = imageLinks?.toResponse(), - ) - -fun EnhancedDocumentVerificationJobResult.toResponse(): Any = when (this) { - is JobResult.Freeform -> this.result - is EnhancedDocumentVerificationJobResult.Entry -> - FlutterEnhancedDocumentVerificationJobResult( - actions = actions.toResponse(), - resultCode = resultCode, - resultText = resultText, - smileJobId = smileJobId, - resultType = resultType, - partnerParams = partnerParams.toResponse(), - antifraud = antifraud?.toResponse(), - dob = dob, - photoBase64 = photoBase64, - gender = gender, - idType = idType, - address = address, - country = country, - documentImageBase64 = documentImageBase64, - fullData = fullData?.mapKeys { it.key }?.mapValues { it.value.toString() }, - fullName = fullName, - idNumber = idNumber, - phoneNumber = phoneNumber, - phoneNumber2 = phoneNumber2, - expirationDate = expirationDate, - ) -} - -fun FlutterProductsConfigRequest.toRequest() = ProductsConfigRequest( - partnerId = partnerId, - timestamp = timestamp, - signature = signature, -) - -fun ProductsConfigResponse.toResponse() = FlutterProductsConfigResponse( - consentRequired = consentRequired.mapKeys { it.key }, - idSelection = idSelection.toResponse(), -) - -fun IdSelection.toResponse() = FlutterIdSelection( - basicKyc = basicKyc.mapKeys { it.key }, - biometricKyc = biometricKyc.mapKeys { it.key }, - enhancedKyc = enhancedKyc.mapKeys { it.key }, - documentVerification = documentVerification.mapKeys { it.key }, -) - -fun ValidDocumentsResponse.toResponse() = FlutterValidDocumentsResponse( - validDocuments = validDocuments.map { it.toResponse() }, -) - -fun ValidDocument.toResponse() = FlutterValidDocument( - country = country.toResponse(), - idTypes = idTypes.map { it.toResponse() }, -) - -fun Country.toResponse() = FlutterCountry( - name = name, - code = code, - continent = continent, -) - -fun IdType.toResponse() = FlutterIdType( - name = name, - code = code, - example = example.map { it }, - hasBack = hasBack, -) - -fun ServicesResponse.toResponse() = FlutterServicesResponse( - bankCodes = bankCodes.map { it.toResponse() }, - hostedWeb = hostedWeb.toResponse(), -) - -fun BankCode.toResponse() = FlutterBankCode( - name = name, - code = code, -) - -fun HostedWeb.toResponse() = FlutterHostedWeb( - basicKyc = basicKyc.groupBy { it.countryCode }.mapValues { it.value.first().toResponse() }, - biometricKyc = - biometricKyc - .groupBy { it.countryCode } - .mapValues { it.value.first().toResponse() }, - enhancedKyc = - enhancedKyc - .groupBy { it.countryCode } - .mapValues { it.value.first().toResponse() }, - documentVerification = - docVerification - .groupBy { it.countryCode } - .mapValues { it.value.first().toResponse() }, - enhancedKycSmartSelfie = - enhancedKycSmartSelfie - .groupBy { it.countryCode } - .mapValues { it.value.first().toResponse() }, - enhancedDocumentVerification = - enhancedDocumentVerification - .groupBy { it.countryCode } - .mapValues { it.value.first().toResponse() }, -) - -fun CountryInfo.toResponse() = FlutterCountryInfo( - countryCode = countryCode, - name = name, - availableIdTypes = availableIdTypes.map { it.toResponse() }, -) - -fun AvailableIdType.toResponse() = FlutterAvailableIdType( - idTypeKey = idTypeKey, - label = label, - requiredFields = requiredFields.map { it.name }, - testData = testData, - idNumberRegex = idNumberRegex, -) - -fun FlutterConfig.toRequest() = Config( - partnerId = partnerId, - authToken = authToken, - prodLambdaUrl = prodBaseUrl, - testLambdaUrl = sandboxBaseUrl, -) diff --git a/android/src/main/kotlin/com/smileidentity/flutter/SmileComposablePlatformView.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileComposablePlatformView.kt deleted file mode 100644 index 507648a..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/SmileComposablePlatformView.kt +++ /dev/null @@ -1,112 +0,0 @@ -package com.smileidentity.flutter - -import android.content.Context -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.ui.platform.ComposeView -import androidx.lifecycle.ViewModelStore -import androidx.lifecycle.ViewModelStoreOwner -import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner -import com.smileidentity.SmileID -import io.flutter.Log -import io.flutter.plugin.common.BinaryMessenger -import io.flutter.plugin.common.MethodChannel -import io.flutter.plugin.platform.PlatformView - -/** - * Base class for hosting Smile ID Composables in Flutter. This class handles flutter<>android - * result delivery, view initialization (incl. view model store), and boilerplate. Subclasses should - * implement [Content] to provide the actual Composable content. - */ -internal abstract class SmileComposablePlatformView( - context: Context, - viewTypeId: String, - viewId: Int, - messenger: BinaryMessenger, - args: Map, -) : PlatformView { - private val methodChannel = MethodChannel(messenger, "${viewTypeId}_$viewId") - - /** - * Creates a viewModelStore that is scoped to the FlutterView's lifecycle. Otherwise, state gets - * shared between multiple FlutterView instances since the default viewModelStore is at the - * Activity level and since we don't have a full Compose app or nav graph, the same viewModel - * ends up getting re-used - */ - private val viewModelStoreOwner = - object : ViewModelStoreOwner { - override val viewModelStore = ViewModelStore() - } - - private var view: ComposeView? = - ComposeView(context).apply { - setContent { - CompositionLocalProvider(LocalViewModelStoreOwner provides viewModelStoreOwner) { - Content(args) - } - } - } - - /** - * Implement this method to provide the actual Composable content for the view - * - * @param args The arguments passed from Flutter. It is the responsibility of the subclass to - * ensure the correct types are provided by the Flutter view and that they are parsed correctly - */ - @Composable - abstract fun Content(args: Map) - - /** - * Delivers a successful result back to Flutter as JSON. It is the flutter code's responsibility - * to parse this JSON string into the appropriate object - * - * @param result The success result object. NB! This object *must* be serializable by the - * [SmileID.moshi] instance! - */ - inline fun onSuccess(result: T) { - // At this point, we have a successful result from the native SDK. But, there is still a - // possibility of the JSON serializing erroring for whatever reason -- if such a thing - // happens, we still want to tell the caller that the overall operation was successful. - // However, we just may not be able to provide the result JSON. - val json = - try { - SmileID.moshi - .adapter(T::class.java) - .toJson(result) - } catch (e: Exception) { - Log.e("SmileComposablePlatformView", "Error serializing result", e) - Log.v("SmileComposablePlatformView", "Result is: $result") - "null" - } - methodChannel.invokeMethod("onSuccess", json) - } - - /** - * Delivers a successful result back to Flutter as JSON. It is the flutter code's responsibility - * to parse this JSON string into the appropriate object - * - * @param result The success result string - */ - fun onSuccessJson(result: String) { - methodChannel.invokeMethod("onSuccess", result) - } - - /** - * Delivers an error result back to Flutter - * - * @param throwable The throwable that caused the error. This will be converted to a string - * message and delivered back to Flutter, because a [Throwable] cannot be passed back to Flutter - */ - fun onError(throwable: Throwable) { - // Print the stack trace, since we can't provide the actual Throwable back to Flutter - throwable.printStackTrace() - methodChannel.invokeMethod("onError", throwable.message) - } - - override fun getView() = view - - override fun dispose() { - // Clear references to the view to avoid memory leaks - view = null - } -} diff --git a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDBiometricKYC.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDBiometricKYC.kt deleted file mode 100644 index edce741..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDBiometricKYC.kt +++ /dev/null @@ -1,111 +0,0 @@ -package com.smileidentity.flutter - -import android.content.Context -import androidx.compose.runtime.Composable -import com.smileidentity.SmileID -import com.smileidentity.compose.BiometricKYC -import com.smileidentity.flutter.results.SmartSelfieCaptureResult -import com.smileidentity.flutter.utils.SelfieCaptureResultAdapter -import com.smileidentity.flutter.utils.getCurrentIsoTimestamp -import com.smileidentity.models.ConsentInformation -import com.smileidentity.models.ConsentedInformation -import com.smileidentity.models.IdInfo -import com.smileidentity.results.SmileIDResult -import com.smileidentity.util.randomJobId -import com.smileidentity.util.randomUserId -import io.flutter.plugin.common.BinaryMessenger -import io.flutter.plugin.common.StandardMessageCodec -import io.flutter.plugin.platform.PlatformView -import io.flutter.plugin.platform.PlatformViewFactory -import kotlinx.collections.immutable.toImmutableMap - -internal class SmileIDBiometricKYC private constructor( - context: Context, - viewId: Int, - messenger: BinaryMessenger, - args: Map, -) : SmileComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { - companion object { - const val VIEW_TYPE_ID = "SmileIDBiometricKYC" - } - - @Composable - override fun Content(args: Map) { - val extraPartnerParams = args["extraPartnerParams"] as? Map ?: emptyMap() - SmileID.BiometricKYC( - idInfo = - IdInfo( - country = args["country"] as? String ?: "", - idType = args["idType"] as? String?, - idNumber = args["idNumber"] as? String?, - firstName = args["firstName"] as? String?, - middleName = args["middleName"] as? String?, - lastName = args["lastName"] as? String?, - dob = args["dob"] as? String?, - bankCode = args["bankCode"] as? String?, - entered = args["entered"] as? Boolean?, - ), - consentInformation = - ConsentInformation( - consented = ConsentedInformation( - consentGrantedDate = args["consentGrantedDate"] as? String - ?: getCurrentIsoTimestamp(), - personalDetails = args["personalDetailsConsentGranted"] as? Boolean == true, - contactInformation = args["contactInfoConsentGranted"] as? Boolean == true, - documentInformation = args["documentInfoConsentGranted"] as? Boolean == true, - ), - ), - userId = args["userId"] as? String ?: randomUserId(), - jobId = args["jobId"] as? String ?: randomJobId(), - allowNewEnroll = args["allowNewEnroll"] as? Boolean ?: false, - allowAgentMode = args["allowAgentMode"] as? Boolean ?: false, - showAttribution = args["showAttribution"] as? Boolean ?: true, - showInstructions = args["showInstructions"] as? Boolean ?: true, - useStrictMode = args["useStrictMode"] as? Boolean ?: true, - extraPartnerParams = extraPartnerParams.toImmutableMap(), - ) { - when (it) { - is SmileIDResult.Success -> { - val result = - SmartSelfieCaptureResult( - selfieFile = it.data.selfieFile, - livenessFiles = it.data.livenessFiles, - didSubmitBiometricKycJob = it.data.didSubmitBiometricKycJob, - ) - val moshi = - SmileID.moshi - .newBuilder() - .add(SelfieCaptureResultAdapter.FACTORY) - .build() - val json = - try { - moshi - .adapter(SmartSelfieCaptureResult::class.java) - .toJson(result) - } catch (e: Exception) { - onError(e) - return@BiometricKYC - } - json?.let { js -> - onSuccessJson(js) - } - } - - is SmileIDResult.Error -> onError(it.throwable) - } - } - } - - class Factory(private val messenger: BinaryMessenger) : - PlatformViewFactory(StandardMessageCodec.INSTANCE) { - override fun create(context: Context, viewId: Int, args: Any?): PlatformView { - @Suppress("UNCHECKED_CAST") - return SmileIDBiometricKYC( - context, - viewId, - messenger, - args as Map, - ) - } - } -} diff --git a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentCaptureView.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentCaptureView.kt deleted file mode 100644 index 7570247..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentCaptureView.kt +++ /dev/null @@ -1,153 +0,0 @@ -package com.smileidentity.flutter - -import android.content.Context -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import com.smileidentity.R -import com.smileidentity.SmileID -import com.smileidentity.compose.document.DocumentCaptureScreen -import com.smileidentity.compose.document.DocumentCaptureSide -import com.smileidentity.compose.theme.colorScheme -import com.smileidentity.compose.theme.typography -import com.smileidentity.flutter.results.DocumentCaptureResult -import com.smileidentity.flutter.utils.DocumentCaptureResultAdapter -import com.smileidentity.util.randomJobId -import io.flutter.plugin.common.BinaryMessenger -import io.flutter.plugin.common.StandardMessageCodec -import io.flutter.plugin.platform.PlatformView -import io.flutter.plugin.platform.PlatformViewFactory -import java.io.File - -internal class SmileIDDocumentCaptureView private constructor( - context: Context, - viewId: Int, - messenger: BinaryMessenger, - args: Map, -) : SmileComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { - companion object { - const val VIEW_TYPE_ID = "SmileIDDocumentCaptureView" - } - - @Composable - override fun Content(args: Map) { - MaterialTheme( - colorScheme = SmileID.colorScheme, - typography = SmileID.typography, - ) { - Surface( - modifier = Modifier.fillMaxSize(), - ) { - val isDocumentFrontSide = args["isDocumentFrontSide"] as? Boolean ?: true - val showInstructions = args["showInstructions"] as? Boolean ?: true - val showAttribution = args["showAttribution"] as? Boolean ?: true - val allowGalleryUpload = args["allowGalleryUpload"] as? Boolean ?: false - val showConfirmationDialog = args["showConfirmationDialog"] as? Boolean ?: true - val idAspectRatio = (args["idAspectRatio"] as Double?)?.toFloat() - RenderDocumentCaptureScreen( - jobId = randomJobId(), - isDocumentFrontSide = isDocumentFrontSide, - showInstructions = showInstructions, - showAttribution = showAttribution, - allowGalleryUpload = allowGalleryUpload, - showConfirmationDialog = showConfirmationDialog, - idAspectRatio = idAspectRatio, - ) - } - } - } - - @Composable - private fun RenderDocumentCaptureScreen( - jobId: String, - isDocumentFrontSide: Boolean, - showInstructions: Boolean, - showAttribution: Boolean, - allowGalleryUpload: Boolean, - showConfirmationDialog: Boolean, - idAspectRatio: Float?, - ) { - val hero = - if (isDocumentFrontSide) { - R.drawable.si_doc_v_front_hero - } else { - R.drawable.si_doc_v_back_hero - } - val instructionTitle = - if (isDocumentFrontSide) { - R.string.si_doc_v_instruction_title - } else { - R.string.si_doc_v_instruction_back_title - } - val instructionSubTitle = - if (isDocumentFrontSide) { - R.string.si_verify_identity_instruction_subtitle - } else { - R.string.si_doc_v_instruction_back_subtitle - } - val captureTitleText = - if (isDocumentFrontSide) { - R.string.si_doc_v_capture_instructions_front_title - } else { - R.string.si_doc_v_capture_instructions_back_title - } - DocumentCaptureScreen( - jobId = jobId, - side = if (isDocumentFrontSide) DocumentCaptureSide.Front else DocumentCaptureSide.Back, - showInstructions = showInstructions, - showAttribution = showAttribution, - allowGallerySelection = allowGalleryUpload, - showConfirmation = showConfirmationDialog, - showSkipButton = false, - instructionsHeroImage = hero, - instructionsTitleText = stringResource(instructionTitle), - instructionsSubtitleText = stringResource(instructionSubTitle), - captureTitleText = stringResource(captureTitleText), - knownIdAspectRatio = idAspectRatio, - onConfirm = { file -> handleConfirmation(isDocumentFrontSide, file) }, - onError = { throwable -> onError(throwable) }, - onSkip = { }, - ) - } - - private fun handleConfirmation(isDocumentFrontSide: Boolean, file: File) { - val moshi = - SmileID.moshi - .newBuilder() - .add(DocumentCaptureResultAdapter.FACTORY) - .build() - val result = - DocumentCaptureResult( - documentFrontFile = if (isDocumentFrontSide) file else null, - documentBackFile = if (!isDocumentFrontSide) file else null, - ) - val json = - try { - moshi - .adapter(DocumentCaptureResult::class.java) - .toJson(result) - } catch (e: Exception) { - onError(e) - return - } - json?.let { - onSuccessJson(it) - } - } - - class Factory(private val messenger: BinaryMessenger) : - PlatformViewFactory(StandardMessageCodec.INSTANCE) { - override fun create(context: Context, viewId: Int, args: Any?): PlatformView { - @Suppress("UNCHECKED_CAST") - return SmileIDDocumentCaptureView( - context, - viewId, - messenger, - args as Map, - ) - } - } -} diff --git a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentVerification.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentVerification.kt deleted file mode 100644 index 25717ae..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentVerification.kt +++ /dev/null @@ -1,96 +0,0 @@ -package com.smileidentity.flutter - -import android.content.Context -import androidx.compose.runtime.Composable -import com.smileidentity.SmileID -import com.smileidentity.compose.DocumentVerification -import com.smileidentity.flutter.results.DocumentCaptureResult -import com.smileidentity.flutter.utils.DocumentCaptureResultAdapter -import com.smileidentity.results.SmileIDResult -import com.smileidentity.util.randomJobId -import com.smileidentity.util.randomUserId -import io.flutter.plugin.common.BinaryMessenger -import io.flutter.plugin.common.StandardMessageCodec -import io.flutter.plugin.platform.PlatformView -import io.flutter.plugin.platform.PlatformViewFactory -import java.io.File -import kotlinx.collections.immutable.toImmutableMap - -internal class SmileIDDocumentVerification private constructor( - context: Context, - viewId: Int, - messenger: BinaryMessenger, - args: Map, -) : SmileComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { - companion object { - const val VIEW_TYPE_ID = "SmileIDDocumentVerification" - } - - @Composable - override fun Content(args: Map) { - val extraPartnerParams = args["extraPartnerParams"] as? Map ?: emptyMap() - SmileID.DocumentVerification( - countryCode = args["countryCode"] as String, - documentType = args["documentType"] as? String, - idAspectRatio = (args["idAspectRatio"] as Double?)?.toFloat(), - captureBothSides = args["captureBothSides"] as? Boolean ?: true, - bypassSelfieCaptureWithFile = - (args["bypassSelfieCaptureWithFile"] as? String)?.let { - File(it) - }, - userId = args["userId"] as? String ?: randomUserId(), - jobId = args["jobId"] as? String ?: randomJobId(), - allowNewEnroll = args["allowNewEnroll"] as? Boolean ?: false, - showAttribution = args["showAttribution"] as? Boolean ?: true, - allowAgentMode = args["allowAgentMode"] as? Boolean ?: false, - allowGalleryUpload = args["allowGalleryUpload"] as? Boolean ?: false, - showInstructions = args["showInstructions"] as? Boolean ?: true, - useStrictMode = args["useStrictMode"] as? Boolean ?: false, - extraPartnerParams = extraPartnerParams.toImmutableMap(), - ) { - when (it) { - is SmileIDResult.Success -> { - val result = - DocumentCaptureResult( - selfieFile = it.data.selfieFile, - documentFrontFile = it.data.documentFrontFile, - livenessFiles = it.data.livenessFiles, - documentBackFile = it.data.documentBackFile, - didSubmitDocumentVerificationJob = - it.data.didSubmitDocumentVerificationJob, - ) - val moshi = - SmileID.moshi - .newBuilder() - .add(DocumentCaptureResultAdapter.FACTORY) - .build() - val json = - try { - moshi.adapter(DocumentCaptureResult::class.java).toJson(result) - } catch (e: Exception) { - onError(e) - return@DocumentVerification - } - json?.let { js -> - onSuccessJson(js) - } - } - - is SmileIDResult.Error -> onError(it.throwable) - } - } - } - - class Factory(private val messenger: BinaryMessenger) : - PlatformViewFactory(StandardMessageCodec.INSTANCE) { - override fun create(context: Context, viewId: Int, args: Any?): PlatformView { - @Suppress("UNCHECKED_CAST") - return SmileIDDocumentVerification( - context, - viewId, - messenger, - args as Map, - ) - } - } -} diff --git a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDEnhancedDocumentVerification.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDEnhancedDocumentVerification.kt deleted file mode 100644 index 403a986..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDEnhancedDocumentVerification.kt +++ /dev/null @@ -1,105 +0,0 @@ -package com.smileidentity.flutter - -import android.content.Context -import androidx.compose.runtime.Composable -import com.smileidentity.SmileID -import com.smileidentity.compose.EnhancedDocumentVerificationScreen -import com.smileidentity.flutter.results.DocumentCaptureResult -import com.smileidentity.flutter.utils.DocumentCaptureResultAdapter -import com.smileidentity.flutter.utils.getCurrentIsoTimestamp -import com.smileidentity.models.ConsentInformation -import com.smileidentity.models.ConsentedInformation -import com.smileidentity.results.SmileIDResult -import com.smileidentity.util.randomJobId -import com.smileidentity.util.randomUserId -import io.flutter.plugin.common.BinaryMessenger -import io.flutter.plugin.common.StandardMessageCodec -import io.flutter.plugin.platform.PlatformView -import io.flutter.plugin.platform.PlatformViewFactory -import kotlinx.collections.immutable.toImmutableMap - -internal class SmileIDEnhancedDocumentVerification private constructor( - context: Context, - viewId: Int, - messenger: BinaryMessenger, - args: Map, -) : SmileComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { - companion object { - const val VIEW_TYPE_ID = "SmileIDEnhancedDocumentVerification" - } - - @Composable - override fun Content(args: Map) { - val extraPartnerParams = args["extraPartnerParams"] as? Map ?: emptyMap() - SmileID.EnhancedDocumentVerificationScreen( - countryCode = args["countryCode"] as String, - documentType = args["documentType"] as? String, - idAspectRatio = (args["idAspectRatio"] as Double?)?.toFloat(), - captureBothSides = args["captureBothSides"] as? Boolean ?: true, - userId = args["userId"] as? String ?: randomUserId(), - jobId = args["jobId"] as? String ?: randomJobId(), - allowNewEnroll = args["allowNewEnroll"] as? Boolean ?: false, - showAttribution = args["showAttribution"] as? Boolean ?: true, - allowAgentMode = args["allowAgentMode"] as? Boolean ?: false, - allowGalleryUpload = args["allowGalleryUpload"] as? Boolean ?: false, - showInstructions = args["showInstructions"] as? Boolean ?: true, - useStrictMode = args["useStrictMode"] as? Boolean ?: false, - consentInformation = - ConsentInformation( - consented = ConsentedInformation( - consentGrantedDate = args["consentGrantedDate"] as? String - ?: getCurrentIsoTimestamp(), - personalDetails = args["personalDetailsConsentGranted"] as? Boolean == true, - contactInformation = args["contactInfoConsentGranted"] as? Boolean == true, - documentInformation = args["documentInfoConsentGranted"] as? Boolean == true, - ), - ), - extraPartnerParams = extraPartnerParams.toImmutableMap(), - ) { - when (it) { - is SmileIDResult.Success -> { - val result = - DocumentCaptureResult( - selfieFile = it.data.selfieFile, - documentFrontFile = it.data.documentFrontFile, - livenessFiles = it.data.livenessFiles, - documentBackFile = it.data.documentBackFile, - didSubmitEnhancedDocVJob = it.data.didSubmitEnhancedDocVJob, - ) - val moshi = - SmileID.moshi - .newBuilder() - .add(DocumentCaptureResultAdapter.FACTORY) - .build() - val json = - try { - moshi - .adapter(DocumentCaptureResult::class.java) - .toJson(result) - } catch (e: Exception) { - onError(e) - return@EnhancedDocumentVerificationScreen - } - json?.let { js -> - onSuccessJson(js) - } - } - - is SmileIDResult.Error -> onError(it.throwable) - } - } - } - - class Factory(private val messenger: BinaryMessenger) : - PlatformViewFactory(StandardMessageCodec.INSTANCE) { - override fun create(context: Context, viewId: Int, args: Any?): PlatformView { - @Suppress("UNCHECKED_CAST") - return SmileIDEnhancedDocumentVerification( - context, - viewId, - messenger, - args as Map, - ) - } - } -} diff --git a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt deleted file mode 100644 index 41fcb42..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt +++ /dev/null @@ -1,470 +0,0 @@ -package com.smileidentity.flutter - -import FlutterAuthenticationRequest -import FlutterAuthenticationResponse -import FlutterBiometricKycJobStatusResponse -import FlutterConfig -import FlutterDocumentVerificationJobStatusResponse -import FlutterEnhancedDocumentVerificationJobStatusResponse -import FlutterEnhancedKycAsyncResponse -import FlutterEnhancedKycRequest -import FlutterEnhancedKycResponse -import FlutterJobStatusRequest -import FlutterPrepUploadRequest -import FlutterPrepUploadResponse -import FlutterProductsConfigRequest -import FlutterProductsConfigResponse -import FlutterServicesResponse -import FlutterSmartSelfieJobStatusResponse -import FlutterSmartSelfieResponse -import FlutterUploadRequest -import FlutterValidDocumentsResponse -import SmileIDApi -import android.app.Activity -import android.content.Context -import com.smileidentity.SmileID -import com.smileidentity.SmileIDOptIn -import com.smileidentity.flutter.enhanced.SmileIDSmartSelfieAuthenticationEnhanced -import com.smileidentity.flutter.enhanced.SmileIDSmartSelfieEnrollmentEnhanced -import com.smileidentity.metadata.models.WrapperSdkName -import com.smileidentity.networking.asFormDataPart -import com.smileidentity.networking.pollBiometricKycJobStatus -import com.smileidentity.networking.pollDocumentVerificationJobStatus -import com.smileidentity.networking.pollEnhancedDocumentVerificationJobStatus -import com.smileidentity.networking.pollSmartSelfieJobStatus -import io.flutter.embedding.engine.plugins.FlutterPlugin -import io.flutter.embedding.engine.plugins.activity.ActivityAware -import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding -import java.io.File -import java.net.URL -import kotlin.time.Duration -import kotlin.time.Duration.Companion.milliseconds -import kotlinx.coroutines.CoroutineExceptionHandler -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.single -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext - -class SmileIDPlugin : - FlutterPlugin, - SmileIDApi, - ActivityAware { - private var activity: Activity? = null - private lateinit var appContext: Context - private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO) - - override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { - SmileIDApi.setUp(flutterPluginBinding.binaryMessenger, this) - appContext = flutterPluginBinding.applicationContext - - // Set wrapper info for Flutter SDK - SmileID.setWrapperInfo(WrapperSdkName.Flutter, "11.0.0") - - flutterPluginBinding.platformViewRegistry.registerViewFactory( - SmileIDDocumentVerification.VIEW_TYPE_ID, - SmileIDDocumentVerification.Factory(flutterPluginBinding.binaryMessenger), - ) - - flutterPluginBinding.platformViewRegistry.registerViewFactory( - SmileIDSmartSelfieEnrollment.VIEW_TYPE_ID, - SmileIDSmartSelfieEnrollment.Factory(flutterPluginBinding.binaryMessenger), - ) - - flutterPluginBinding.platformViewRegistry.registerViewFactory( - SmileIDSmartSelfieAuthentication.VIEW_TYPE_ID, - SmileIDSmartSelfieAuthentication.Factory(flutterPluginBinding.binaryMessenger), - ) - - flutterPluginBinding.platformViewRegistry.registerViewFactory( - SmileIDSmartSelfieEnrollmentEnhanced.VIEW_TYPE_ID, - SmileIDSmartSelfieEnrollmentEnhanced.Factory(flutterPluginBinding.binaryMessenger), - ) - - flutterPluginBinding.platformViewRegistry.registerViewFactory( - SmileIDSmartSelfieAuthenticationEnhanced.VIEW_TYPE_ID, - SmileIDSmartSelfieAuthenticationEnhanced.Factory(flutterPluginBinding.binaryMessenger), - ) - - flutterPluginBinding.platformViewRegistry.registerViewFactory( - SmileIDBiometricKYC.VIEW_TYPE_ID, - SmileIDBiometricKYC.Factory(flutterPluginBinding.binaryMessenger), - ) - - flutterPluginBinding.platformViewRegistry.registerViewFactory( - SmileIDEnhancedDocumentVerification.VIEW_TYPE_ID, - SmileIDEnhancedDocumentVerification.Factory(flutterPluginBinding.binaryMessenger), - ) - - flutterPluginBinding.platformViewRegistry.registerViewFactory( - SmileIDSmartSelfieCaptureView.VIEW_TYPE_ID, - SmileIDSmartSelfieCaptureView.Factory(flutterPluginBinding.binaryMessenger), - ) - - flutterPluginBinding.platformViewRegistry.registerViewFactory( - SmileIDDocumentCaptureView.VIEW_TYPE_ID, - SmileIDDocumentCaptureView.Factory(flutterPluginBinding.binaryMessenger), - ) - } - - override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { - SmileIDApi.setUp(binding.binaryMessenger, null) - } - - override fun initializeWithApiKey( - apiKey: String, - config: FlutterConfig, - useSandbox: Boolean, - enableCrashReporting: Boolean, - ) { - SmileID.initialize( - context = appContext, - apiKey = apiKey, - config = config.toRequest(), - useSandbox = useSandbox, - enableCrashReporting = false, - ) - } - - override fun initializeWithConfig( - config: FlutterConfig, - useSandbox: Boolean, - enableCrashReporting: Boolean, - ) { - SmileID.initialize( - context = appContext, - config = config.toRequest(), - useSandbox = useSandbox, - enableCrashReporting = false, - ) - } - - override fun initialize(useSandbox: Boolean) { - SmileID.initialize( - context = appContext, - useSandbox = useSandbox, - ) - } - - override fun setCallbackUrl(callbackUrl: String) { - SmileID.setCallbackUrl(callbackUrl = URL(callbackUrl)) - } - - override fun setAllowOfflineMode(allowOfflineMode: Boolean) { - SmileID.setAllowOfflineMode(allowOfflineMode = allowOfflineMode) - } - - override fun getSubmittedJobs(): List = SmileID.getSubmittedJobs() - - override fun getUnsubmittedJobs(): List = SmileID.getUnsubmittedJobs() - - override fun cleanup(jobId: String) { - SmileID.cleanup(jobId = jobId) - } - - override fun cleanupJobs(jobIds: List) { - SmileID.cleanup(jobIds = jobIds) - } - - override fun submitJob(jobId: String, deleteFilesOnSuccess: Boolean) { - scope.launch { - SmileID.submitJob(jobId = jobId, deleteFilesOnSuccess = deleteFilesOnSuccess) - } - } - - override fun authenticate( - request: FlutterAuthenticationRequest, - callback: (Result) -> Unit, - ) = launch( - work = { SmileID.api.authenticate(request.toRequest()).toResponse() }, - callback = callback, - ) - - override fun prepUpload( - request: FlutterPrepUploadRequest, - callback: (Result) -> Unit, - ) = launch( - work = { SmileID.api.prepUpload(request.toRequest()).toResponse() }, - callback = callback, - ) - - override fun upload( - url: String, - request: FlutterUploadRequest, - callback: (Result) -> Unit, - ) = launch( - work = { SmileID.api.upload(url, request.toRequest()) }, - callback = callback, - ) - - override fun doEnhancedKyc( - request: FlutterEnhancedKycRequest, - callback: (Result) -> Unit, - ) = launch( - work = { SmileID.api.doEnhancedKyc(request.toRequest()).toResponse() }, - callback = callback, - ) - - override fun doEnhancedKycAsync( - request: FlutterEnhancedKycRequest, - callback: (Result) -> Unit, - ) = launch( - work = { SmileID.api.doEnhancedKycAsync(request.toRequest()).toResponse() }, - callback = callback, - ) - - override fun getSmartSelfieJobStatus( - request: FlutterJobStatusRequest, - callback: (Result) -> Unit, - ) = launch( - work = { SmileID.api.getSmartSelfieJobStatus(request.toRequest()).toResponse() }, - callback = callback, - ) - - @OptIn(SmileIDOptIn::class) - override fun doSmartSelfieEnrollment( - signature: String, - timestamp: String, - selfieImage: String, - livenessImages: List, - userId: String, - partnerParams: Map?, - callbackUrl: String?, - sandboxResult: Long?, - allowNewEnroll: Boolean?, - callback: (Result) -> Unit, - ) = launch( - work = { - SmileID.api - .doSmartSelfieEnrollment( - userId = userId, - selfieImage = - File(selfieImage).asFormDataPart( - partName = "selfie_image", - mediaType = "image/jpeg", - ), - livenessImages = - livenessImages.map { - File(selfieImage).asFormDataPart( - partName = "liveness_images", - mediaType = "image/jpeg", - ) - }, - partnerParams = convertNullableMapToNonNull(partnerParams), - callbackUrl = callbackUrl, - sandboxResult = sandboxResult?.toInt(), - allowNewEnroll = allowNewEnroll, - ).toResponse() - }, - callback = callback, - ) - - @OptIn(SmileIDOptIn::class) - override fun doSmartSelfieAuthentication( - signature: String, - timestamp: String, - selfieImage: String, - livenessImages: List, - userId: String, - partnerParams: Map?, - callbackUrl: String?, - sandboxResult: Long?, - callback: (Result) -> Unit, - ) = launch( - work = { - SmileID.api - .doSmartSelfieAuthentication( - userId = userId, - selfieImage = - File(selfieImage).asFormDataPart( - partName = "selfie_image", - mediaType = "image/jpeg", - ), - livenessImages = - livenessImages.map { - File(selfieImage).asFormDataPart( - partName = "liveness_images", - mediaType = "image/jpeg", - ) - }, - partnerParams = convertNullableMapToNonNull(partnerParams), - callbackUrl = callbackUrl, - sandboxResult = sandboxResult?.toInt(), - ).toResponse() - }, - callback = callback, - ) - - override fun getDocumentVerificationJobStatus( - request: FlutterJobStatusRequest, - callback: (Result) -> Unit, - ) = launch( - work = { SmileID.api.getDocumentVerificationJobStatus(request.toRequest()).toResponse() }, - callback = callback, - ) - - override fun getBiometricKycJobStatus( - request: FlutterJobStatusRequest, - callback: (Result) -> Unit, - ) = launch( - work = { SmileID.api.getBiometricKycJobStatus(request.toRequest()).toResponse() }, - callback = callback, - ) - - override fun getEnhancedDocumentVerificationJobStatus( - request: FlutterJobStatusRequest, - callback: (Result) -> Unit, - ) = launch( - work = { - SmileID.api.getEnhancedDocumentVerificationJobStatus(request.toRequest()).toResponse() - }, - callback = callback, - ) - - override fun getProductsConfig( - request: FlutterProductsConfigRequest, - callback: (Result) -> Unit, - ) = launch( - work = { SmileID.api.getProductsConfig(request.toRequest()).toResponse() }, - callback = callback, - ) - - override fun getValidDocuments( - request: FlutterProductsConfigRequest, - callback: (Result) -> Unit, - ) = launch( - work = { SmileID.api.getValidDocuments(request.toRequest()).toResponse() }, - callback = callback, - ) - - override fun getServices(callback: (Result) -> Unit) = launch( - work = { SmileID.api.getServices().toResponse() }, - callback = callback, - ) - - override fun pollSmartSelfieJobStatus( - request: FlutterJobStatusRequest, - interval: Long, - numAttempts: Long, - callback: (Result) -> Unit, - ) = launch( - work = { - pollJobStatus( - apiCall = SmileID.api::pollSmartSelfieJobStatus, - request = request.toRequest(), - interval = interval, - numAttempts = numAttempts, - transform = { it.toResponse() }, - ) - }, - callback = callback, - ) - - override fun pollDocumentVerificationJobStatus( - request: FlutterJobStatusRequest, - interval: Long, - numAttempts: Long, - callback: (Result) -> Unit, - ) = launch( - work = { - pollJobStatus( - apiCall = SmileID.api::pollDocumentVerificationJobStatus, - request = request.toRequest(), - interval = interval, - numAttempts = numAttempts, - transform = { it.toResponse() }, - ) - }, - callback = callback, - ) - - override fun pollBiometricKycJobStatus( - request: FlutterJobStatusRequest, - interval: Long, - numAttempts: Long, - callback: (Result) -> Unit, - ) = launch( - work = { - pollJobStatus( - apiCall = SmileID.api::pollBiometricKycJobStatus, - request = request.toRequest(), - interval = interval, - numAttempts = numAttempts, - transform = { it.toResponse() }, - ) - }, - callback = callback, - ) - - override fun pollEnhancedDocumentVerificationJobStatus( - request: FlutterJobStatusRequest, - interval: Long, - numAttempts: Long, - callback: (Result) -> Unit, - ) = launch( - work = { - pollJobStatus( - apiCall = SmileID.api::pollEnhancedDocumentVerificationJobStatus, - request = request.toRequest(), - interval = interval, - numAttempts = numAttempts, - transform = { it.toResponse() }, - ) - }, - callback = callback, - ) - - private suspend fun pollJobStatus( - apiCall: suspend (RequestType, Duration, Int) -> Flow, - request: RequestType, - interval: Long, - numAttempts: Long, - transform: (ResponseType) -> FlutterResponseType, - ): FlutterResponseType = try { - val response = - withContext(Dispatchers.IO) { - apiCall(request, interval.milliseconds, numAttempts.toInt()) - .map { transform(it) } - .single() - } - response - } catch (e: Exception) { - throw e - } - - /** - * https://stackoverflow.com/a/62206235 - * - * We can get the context in a ActivityAware way, without asking users to pass the context when - * calling "initialize" on the sdk - */ - override fun onAttachedToActivity(binding: ActivityPluginBinding) { - this.activity = binding.activity - } - - override fun onDetachedFromActivityForConfigChanges() {} - - override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {} - - override fun onDetachedFromActivity() {} -} - -/** - * Launches a new coroutine in the specified dispatcher (IO by default) and returns the result to - * the callback. Used for launching coroutines from Dart. - */ -private fun launch( - work: suspend () -> T, - callback: (Result) -> Unit, - scope: CoroutineScope = CoroutineScope(Dispatchers.IO), -) { - val handler = - CoroutineExceptionHandler { _, throwable -> - callback.invoke(Result.failure(throwable)) - } - scope.launch(handler) { - callback.invoke(Result.success(work())) - } -} diff --git a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieAuthentication.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieAuthentication.kt deleted file mode 100644 index 563877c..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieAuthentication.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.smileidentity.flutter - -import android.content.Context -import androidx.compose.runtime.Composable -import com.smileidentity.SmileID -import com.smileidentity.compose.SmartSelfieAuthentication -import com.smileidentity.util.randomUserId -import io.flutter.plugin.common.BinaryMessenger -import io.flutter.plugin.common.StandardMessageCodec -import io.flutter.plugin.platform.PlatformView -import io.flutter.plugin.platform.PlatformViewFactory -import kotlinx.collections.immutable.toImmutableMap - -internal class SmileIDSmartSelfieAuthentication private constructor( - context: Context, - viewId: Int, - messenger: BinaryMessenger, - args: Map, -) : SmileSelfieComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { - companion object { - const val VIEW_TYPE_ID = "SmileIDSmartSelfieAuthentication" - } - - @Composable - override fun Content(args: Map) { - val extraPartnerParams = args["extraPartnerParams"] as? Map ?: emptyMap() - SmileID.SmartSelfieAuthentication( - userId = args["userId"] as? String ?: randomUserId(), - allowNewEnroll = args["allowNewEnroll"] as? Boolean ?: false, - allowAgentMode = args["allowAgentMode"] as? Boolean ?: false, - showAttribution = args["showAttribution"] as? Boolean ?: true, - showInstructions = args["showInstructions"] as? Boolean ?: true, - skipApiSubmission = args["skipApiSubmission"] as? Boolean ?: false, - extraPartnerParams = extraPartnerParams.toImmutableMap(), - onResult = { res -> handleResult(res) }, - ) - } - - class Factory(private val messenger: BinaryMessenger) : - PlatformViewFactory(StandardMessageCodec.INSTANCE) { - override fun create(context: Context, viewId: Int, args: Any?): PlatformView { - @Suppress("UNCHECKED_CAST") - return SmileIDSmartSelfieAuthentication( - context, - viewId, - messenger, - args as Map, - ) - } - } -} diff --git a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieCaptureView.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieCaptureView.kt deleted file mode 100644 index b644b24..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieCaptureView.kt +++ /dev/null @@ -1,197 +0,0 @@ -package com.smileidentity.flutter - -import android.content.Context -import android.graphics.BitmapFactory -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.consumeWindowInsets -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.statusBars -import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.asImageBitmap -import androidx.compose.ui.graphics.painter.BitmapPainter -import androidx.compose.ui.res.stringResource -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.viewmodel.compose.viewModel -import com.smileidentity.R -import com.smileidentity.SmileID -import com.smileidentity.SmileIDOptIn -import com.smileidentity.compose.SmartSelfieEnrollmentEnhanced -import com.smileidentity.compose.components.ImageCaptureConfirmationDialog -import com.smileidentity.compose.selfie.SelfieCaptureScreen -import com.smileidentity.compose.selfie.SmartSelfieInstructionsScreen -import com.smileidentity.compose.theme.colorScheme -import com.smileidentity.compose.theme.typography -import com.smileidentity.util.randomJobId -import com.smileidentity.util.randomUserId -import com.smileidentity.viewmodel.SelfieUiState -import com.smileidentity.viewmodel.SelfieViewModel -import com.smileidentity.viewmodel.viewModelFactory -import io.flutter.plugin.common.BinaryMessenger -import io.flutter.plugin.common.StandardMessageCodec -import io.flutter.plugin.platform.PlatformView -import io.flutter.plugin.platform.PlatformViewFactory - -internal class SmileIDSmartSelfieCaptureView private constructor( - context: Context, - viewId: Int, - messenger: BinaryMessenger, - args: Map, -) : SmileSelfieComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { - companion object { - const val VIEW_TYPE_ID = "SmileIDSmartSelfieCaptureView" - } - - @OptIn(SmileIDOptIn::class) - @Composable - override fun Content(args: Map) { - val showConfirmationDialog = args["showConfirmationDialog"] as? Boolean ?: true - val showInstructions = args["showInstructions"] as? Boolean ?: true - val showAttribution = args["showAttribution"] as? Boolean ?: true - val allowAgentMode = args["allowAgentMode"] as? Boolean ?: true - val useStrictMode = args["useStrictMode"] as? Boolean ?: false - var acknowledgedInstructions by rememberSaveable { mutableStateOf(false) } - val userId = randomUserId() - val jobId = randomJobId() - - MaterialTheme(colorScheme = SmileID.colorScheme, typography = SmileID.typography) { - Surface( - content = { - if (useStrictMode) { - // Enhanced mode doesn't support confirmation dialog - SmileID.SmartSelfieEnrollmentEnhanced( - userId = userId, - showAttribution = showAttribution, - showInstructions = showInstructions, - skipApiSubmission = true, - onResult = { res -> handleResult(res) }, - ) - } else { - // Custom implementation for regular mode with confirmation dialog support - val viewModel: SelfieViewModel = viewModel( - factory = viewModelFactory { - SelfieViewModel( - isEnroll = true, - userId = userId, - jobId = jobId, - allowNewEnroll = true, - skipApiSubmission = true, - metadata = mutableListOf(), - ) - }, - ) - - val uiState = viewModel.uiState.collectAsStateWithLifecycle().value - - when { - showInstructions && !acknowledgedInstructions -> - SmartSelfieInstructionsScreen( - showAttribution = showAttribution, - ) { - acknowledgedInstructions = true - } - uiState.processingState != null -> HandleProcessingState(viewModel) - uiState.selfieToConfirm != null -> - HandleSelfieConfirmation( - showConfirmationDialog, - uiState, - viewModel, - ) - else -> RenderSelfieCaptureScreen( - userId, - jobId, - allowAgentMode, - viewModel, - ) - } - } - }, - ) - } - } - - @Composable - private fun RenderSelfieCaptureScreen( - userId: String, - jobId: String, - allowAgentMode: Boolean, - viewModel: SelfieViewModel, - ) { - Box( - modifier = Modifier - .background(color = Color.White) - .windowInsetsPadding(WindowInsets.statusBars) - .consumeWindowInsets(WindowInsets.statusBars) - .fillMaxSize(), - ) { - SelfieCaptureScreen( - userId = userId, - jobId = jobId, - allowAgentMode = allowAgentMode, - allowNewEnroll = true, - skipApiSubmission = true, - viewModel = viewModel, - ) - } - } - - @Composable - private fun HandleSelfieConfirmation( - showConfirmation: Boolean, - uiState: SelfieUiState, - viewModel: SelfieViewModel, - ) { - if (showConfirmation) { - ImageCaptureConfirmationDialog( - titleText = stringResource(R.string.si_smart_selfie_confirmation_dialog_title), - subtitleText = stringResource( - R.string.si_smart_selfie_confirmation_dialog_subtitle, - ), - painter = BitmapPainter( - BitmapFactory - .decodeFile(uiState.selfieToConfirm!!.absolutePath) - .asImageBitmap(), - ), - confirmButtonText = stringResource( - R.string.si_smart_selfie_confirmation_dialog_confirm_button, - ), - onConfirm = { viewModel.submitJob() }, - retakeButtonText = stringResource( - R.string.si_smart_selfie_confirmation_dialog_retake_button, - ), - onRetake = viewModel::onSelfieRejected, - scaleFactor = 1.25f, - ) - } else { - viewModel.submitJob() - } - } - - @Composable - private fun HandleProcessingState(viewModel: SelfieViewModel) { - viewModel.onFinished { res -> handleResult(res) } - } - - class Factory(private val messenger: BinaryMessenger) : - PlatformViewFactory(StandardMessageCodec.INSTANCE) { - override fun create(context: Context, viewId: Int, args: Any?): PlatformView { - @Suppress("UNCHECKED_CAST") - return SmileIDSmartSelfieCaptureView( - context, - viewId, - messenger, - args as Map, - ) - } - } -} diff --git a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieEnrollment.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieEnrollment.kt deleted file mode 100644 index 90aa890..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieEnrollment.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.smileidentity.flutter - -import android.content.Context -import androidx.compose.runtime.Composable -import com.smileidentity.SmileID -import com.smileidentity.compose.SmartSelfieEnrollment -import com.smileidentity.util.randomUserId -import io.flutter.plugin.common.BinaryMessenger -import io.flutter.plugin.common.StandardMessageCodec -import io.flutter.plugin.platform.PlatformView -import io.flutter.plugin.platform.PlatformViewFactory -import kotlinx.collections.immutable.toImmutableMap - -internal class SmileIDSmartSelfieEnrollment private constructor( - context: Context, - viewId: Int, - messenger: BinaryMessenger, - args: Map, -) : SmileSelfieComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { - companion object { - const val VIEW_TYPE_ID = "SmileIDSmartSelfieEnrollment" - } - - @Composable - override fun Content(args: Map) { - val extraPartnerParams = args["extraPartnerParams"] as? Map ?: emptyMap() - SmileID.SmartSelfieEnrollment( - userId = args["userId"] as? String ?: randomUserId(), - allowNewEnroll = args["allowNewEnroll"] as? Boolean ?: false, - allowAgentMode = args["allowAgentMode"] as? Boolean ?: false, - showAttribution = args["showAttribution"] as? Boolean ?: true, - showInstructions = args["showInstructions"] as? Boolean ?: true, - skipApiSubmission = args["skipApiSubmission"] as? Boolean ?: false, - extraPartnerParams = extraPartnerParams.toImmutableMap(), - onResult = { res -> handleResult(res) }, - ) - } - - class Factory(private val messenger: BinaryMessenger) : - PlatformViewFactory(StandardMessageCodec.INSTANCE) { - override fun create(context: Context, viewId: Int, args: Any?): PlatformView { - @Suppress("UNCHECKED_CAST") - return SmileIDSmartSelfieEnrollment( - context, - viewId, - messenger, - args as Map, - ) - } - } -} diff --git a/android/src/main/kotlin/com/smileidentity/flutter/SmileSelfieComposablePlatformView.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileSelfieComposablePlatformView.kt deleted file mode 100644 index 0e69880..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/SmileSelfieComposablePlatformView.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.smileidentity.flutter - -import android.content.Context -import com.smileidentity.SmileID -import com.smileidentity.flutter.results.SmartSelfieCaptureResult -import com.smileidentity.flutter.utils.SelfieCaptureResultAdapter -import com.smileidentity.results.SmartSelfieResult -import com.smileidentity.results.SmileIDResult -import io.flutter.plugin.common.BinaryMessenger - -internal abstract class SmileSelfieComposablePlatformView( - context: Context, - viewTypeId: String, - viewId: Int, - messenger: BinaryMessenger, - args: Map, -) : SmileComposablePlatformView(context, viewTypeId, viewId, messenger, args) { - protected fun handleResult(res: SmileIDResult) { - when (res) { - is SmileIDResult.Success -> { - val result = - SmartSelfieCaptureResult( - selfieFile = res.data.selfieFile, - livenessFiles = res.data.livenessFiles, - apiResponse = res.data.apiResponse, - ) - val moshi = - SmileID.moshi - .newBuilder() - .add(SelfieCaptureResultAdapter.FACTORY) - .build() - val json = - try { - moshi - .adapter(SmartSelfieCaptureResult::class.java) - .toJson(result) - } catch (e: Exception) { - onError(e) - return - } - json?.let { js -> - onSuccessJson(js) - } - } - - is SmileIDResult.Error -> onError(res.throwable) - } - } -} diff --git a/android/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieAuthenticationEnhanced.kt b/android/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieAuthenticationEnhanced.kt deleted file mode 100644 index 83976ab..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieAuthenticationEnhanced.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.smileidentity.flutter.enhanced - -import android.content.Context -import androidx.compose.runtime.Composable -import com.smileidentity.SmileID -import com.smileidentity.compose.SmartSelfieAuthenticationEnhanced -import com.smileidentity.flutter.SmileSelfieComposablePlatformView -import com.smileidentity.util.randomUserId -import io.flutter.plugin.common.BinaryMessenger -import io.flutter.plugin.common.StandardMessageCodec -import io.flutter.plugin.platform.PlatformView -import io.flutter.plugin.platform.PlatformViewFactory -import kotlinx.collections.immutable.toImmutableMap - -internal class SmileIDSmartSelfieAuthenticationEnhanced private constructor( - context: Context, - viewId: Int, - messenger: BinaryMessenger, - args: Map, -) : SmileSelfieComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { - companion object { - const val VIEW_TYPE_ID = "SmileIDSmartSelfieAuthenticationEnhanced" - } - - @Composable - override fun Content(args: Map) { - val extraPartnerParams = args["extraPartnerParams"] as? Map ?: emptyMap() - SmileID.SmartSelfieAuthenticationEnhanced( - userId = args["userId"] as? String ?: randomUserId(), - allowNewEnroll = args["allowNewEnroll"] as? Boolean ?: false, - showAttribution = args["showAttribution"] as? Boolean ?: true, - showInstructions = args["showInstructions"] as? Boolean ?: true, - skipApiSubmission = args["skipApiSubmission"] as? Boolean ?: false, - extraPartnerParams = extraPartnerParams.toImmutableMap(), - onResult = { res -> handleResult(res) }, - ) - } - - class Factory(private val messenger: BinaryMessenger) : - PlatformViewFactory(StandardMessageCodec.INSTANCE) { - override fun create(context: Context, viewId: Int, args: Any?): PlatformView { - @Suppress("UNCHECKED_CAST") - return SmileIDSmartSelfieAuthenticationEnhanced( - context, - viewId, - messenger, - args as Map, - ) - } - } -} diff --git a/android/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieEnrollmentEnhanced.kt b/android/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieEnrollmentEnhanced.kt deleted file mode 100644 index d1d08fb..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieEnrollmentEnhanced.kt +++ /dev/null @@ -1,51 +0,0 @@ -package com.smileidentity.flutter.enhanced - -import android.content.Context -import androidx.compose.runtime.Composable -import com.smileidentity.SmileID -import com.smileidentity.compose.SmartSelfieEnrollmentEnhanced -import com.smileidentity.flutter.SmileSelfieComposablePlatformView -import com.smileidentity.util.randomUserId -import io.flutter.plugin.common.BinaryMessenger -import io.flutter.plugin.common.StandardMessageCodec -import io.flutter.plugin.platform.PlatformView -import io.flutter.plugin.platform.PlatformViewFactory -import kotlinx.collections.immutable.toImmutableMap - -internal class SmileIDSmartSelfieEnrollmentEnhanced private constructor( - context: Context, - viewId: Int, - messenger: BinaryMessenger, - args: Map, -) : SmileSelfieComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { - companion object { - const val VIEW_TYPE_ID = "SmileIDSmartSelfieEnrollmentEnhanced" - } - - @Composable - override fun Content(args: Map) { - val extraPartnerParams = args["extraPartnerParams"] as? Map ?: emptyMap() - SmileID.SmartSelfieEnrollmentEnhanced( - userId = args["userId"] as? String ?: randomUserId(), - allowNewEnroll = args["allowNewEnroll"] as? Boolean ?: false, - showAttribution = args["showAttribution"] as? Boolean ?: true, - showInstructions = args["showInstructions"] as? Boolean ?: true, - skipApiSubmission = args["skipApiSubmission"] as? Boolean ?: false, - extraPartnerParams = extraPartnerParams.toImmutableMap(), - onResult = { res -> handleResult(res) }, - ) - } - - class Factory(private val messenger: BinaryMessenger) : - PlatformViewFactory(StandardMessageCodec.INSTANCE) { - override fun create(context: Context, viewId: Int, args: Any?): PlatformView { - @Suppress("UNCHECKED_CAST") - return SmileIDSmartSelfieEnrollmentEnhanced( - context, - viewId, - messenger, - args as Map, - ) - } - } -} diff --git a/android/src/main/kotlin/com/smileidentity/flutter/generated/SmileIDMessages.g.kt b/android/src/main/kotlin/com/smileidentity/flutter/generated/SmileIDMessages.g.kt deleted file mode 100644 index 78f17ec..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/generated/SmileIDMessages.g.kt +++ /dev/null @@ -1,2864 +0,0 @@ -// Autogenerated from Pigeon (v16.0.5), do not edit directly. -// See also: https://pub.dev/packages/pigeon - -import android.util.Log -import io.flutter.plugin.common.BasicMessageChannel -import io.flutter.plugin.common.BinaryMessenger -import io.flutter.plugin.common.MessageCodec -import io.flutter.plugin.common.StandardMessageCodec -import java.io.ByteArrayOutputStream -import java.nio.ByteBuffer - -private fun wrapResult(result: Any?): List = listOf(result) - -private fun wrapError(exception: Throwable): List { - if (exception is SmileFlutterError) { - return listOf( - exception.code, - exception.message, - exception.details, - ) - } else { - return listOf( - exception.javaClass.simpleName, - exception.toString(), - "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception), - ) - } -} - -/** - * Error class for passing custom error details to Flutter via a thrown PlatformException. - * @property code The error code. - * @property message The error message. - * @property details The error details. Must be a datatype supported by the api codec. - */ -class SmileFlutterError( - val code: String, - override val message: String? = null, - val details: Any? = null, -) : Throwable() - -enum class FlutterJobType(val raw: Int) { - ENHANCEDKYC(0), - DOCUMENTVERIFICATION(1), - BIOMETRICKYC(2), - ENHANCEDDOCUMENTVERIFICATION(3), - SMARTSELFIEENROLLMENT(4), - SMARTSELFIEAUTHENTICATION(5), - ; - - companion object { - fun ofRaw(raw: Int): FlutterJobType? = values().firstOrNull { it.raw == raw } - } -} - -enum class FlutterJobTypeV2(val raw: Int) { - SMARTSELFIEAUTHENTICATION(0), - SMARTSELFIEENROLLMENT(1), - ; - - companion object { - fun ofRaw(raw: Int): FlutterJobTypeV2? = values().firstOrNull { it.raw == raw } - } -} - -enum class FlutterImageType(val raw: Int) { - SELFIEJPGFILE(0), - IDCARDJPGFILE(1), - SELFIEJPGBASE64(2), - IDCARDJPGBASE64(3), - LIVENESSJPGFILE(4), - IDCARDREARJPGFILE(5), - LIVENESSJPGBASE64(6), - IDCARDREARJPGBASE64(7), - ; - - companion object { - fun ofRaw(raw: Int): FlutterImageType? = values().firstOrNull { it.raw == raw } - } -} - -enum class FlutterActionResult(val raw: Int) { - PASSED(0), - COMPLETED(1), - APPROVED(2), - VERIFIED(3), - PROVISIONALLYAPPROVED(4), - RETURNED(5), - NOTRETURNED(6), - FAILED(7), - REJECTED(8), - UNDERREVIEW(9), - UNABLETODETERMINE(10), - NOTAPPLICABLE(11), - NOTVERIFIED(12), - NOTDONE(13), - ISSUERUNAVAILABLE(14), - IDAUTHORITYPHOTONOTAVAILABLE(15), - SENTTOHUMANREVIEW(16), - UNKNOWN(17), - ; - - companion object { - fun ofRaw(raw: Int): FlutterActionResult? = values().firstOrNull { it.raw == raw } - } -} - -enum class FlutterSmartSelfieStatus(val raw: Int) { - APPROVED(0), - PENDING(1), - REJECTED(2), - UNKNOWN(3), - ; - - companion object { - fun ofRaw(raw: Int): FlutterSmartSelfieStatus? = values().firstOrNull { it.raw == raw } - } -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterConsentInformation( - val consentGrantedDate: String, - val personalDetailsConsentGranted: Boolean, - val contactInfoConsentGranted: Boolean, - val documentInfoConsentGranted: Boolean, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterConsentInformation { - val consentGrantedDate = list[0] as String - val personalDetailsConsentGranted = list[1] as Boolean - val contactInfoConsentGranted = list[2] as Boolean - val documentInfoConsentGranted = list[3] as Boolean - return FlutterConsentInformation( - consentGrantedDate, - personalDetailsConsentGranted, - contactInfoConsentGranted, - documentInfoConsentGranted, - ) - } - } - fun toList(): List = listOf( - consentGrantedDate, - personalDetailsConsentGranted, - contactInfoConsentGranted, - documentInfoConsentGranted, - ) -} - -/** - * Custom values specific to partners can be placed in [extras] - * - * Generated class from Pigeon that represents data sent in messages. - */ -data class FlutterPartnerParams( - val jobType: FlutterJobType? = null, - val jobId: String, - val userId: String, - val extras: Map? = null, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterPartnerParams { - val jobType: FlutterJobType? = (list[0] as Int?)?.let { - FlutterJobType.ofRaw(it) - } - val jobId = list[1] as String - val userId = list[2] as String - val extras = list[3] as Map? - return FlutterPartnerParams(jobType, jobId, userId, extras) - } - } - fun toList(): List = listOf( - jobType?.raw, - jobId, - userId, - extras, - ) -} - -/** - * The Auth Smile request. Auth Smile serves multiple purposes: - * - * - It is used to fetch the signature needed for subsequent API requests - * - It indicates the type of job that will being performed - * - It is used to fetch consent information for the partner - * - * [jobType] The type of job that will be performed - * [country] The country code of the country where the job is being performed. This value is - * required in order to get back consent information for the partner - * [idType] The type of ID that will be used for the job. This value is required in order to - * get back consent information for the partner - * [updateEnrolledImage] Whether or not the enrolled image should be updated with image - * submitted for this job - * [jobId] The job ID to associate with the job. Most often, this will correspond to a unique - * Job ID within your own system. If not provided, a random job ID will be generated - * [userId] The user ID to associate with the job. Most often, this will correspond to a unique - * User ID within your own system. If not provided, a random user ID will be generated - * - * Generated class from Pigeon that represents data sent in messages. - */ -data class FlutterAuthenticationRequest( - val jobType: FlutterJobType, - val country: String? = null, - val idType: String? = null, - val updateEnrolledImage: Boolean? = null, - val jobId: String? = null, - val userId: String? = null, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterAuthenticationRequest { - val jobType = FlutterJobType.ofRaw(list[0] as Int)!! - val country = list[1] as String? - val idType = list[2] as String? - val updateEnrolledImage = list[3] as Boolean? - val jobId = list[4] as String? - val userId = list[5] as String? - return FlutterAuthenticationRequest( - jobType, - country, - idType, - updateEnrolledImage, - jobId, - userId, - ) - } - } - fun toList(): List = listOf( - jobType.raw, - country, - idType, - updateEnrolledImage, - jobId, - userId, - ) -} - -/** - * [consentInfo] is only populated when a country and ID type are provided in the - * [FlutterAuthenticationRequest]. To get information about *all* countries and ID types instead, - * [SmileIDService.getProductsConfig] - * - * [timestamp] is *not* a [DateTime] because technically, any arbitrary value could have been - * passed to it. This applies to all other timestamp fields in the SDK. - * - * Generated class from Pigeon that represents data sent in messages. - */ -data class FlutterAuthenticationResponse( - val success: Boolean, - val signature: String, - val timestamp: String, - val partnerParams: FlutterPartnerParams, - val callbackUrl: String? = null, - val consentInfo: FlutterConsentInfo? = null, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterAuthenticationResponse { - val success = list[0] as Boolean - val signature = list[1] as String - val timestamp = list[2] as String - val partnerParams = FlutterPartnerParams.fromList(list[3] as List) - val callbackUrl = list[4] as String? - val consentInfo: FlutterConsentInfo? = (list[5] as List?)?.let { - FlutterConsentInfo.fromList(it) - } - return FlutterAuthenticationResponse( - success, - signature, - timestamp, - partnerParams, - callbackUrl, - consentInfo, - ) - } - } - fun toList(): List = listOf( - success, - signature, - timestamp, - partnerParams.toList(), - callbackUrl, - consentInfo?.toList(), - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterPrepUploadRequest( - val partnerParams: FlutterPartnerParams, - val callbackUrl: String? = null, - val allowNewEnroll: Boolean, - val partnerId: String, - val timestamp: String, - val signature: String, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterPrepUploadRequest { - val partnerParams = FlutterPartnerParams.fromList(list[0] as List) - val callbackUrl = list[1] as String? - val allowNewEnroll = list[2] as Boolean - val partnerId = list[3] as String - val timestamp = list[4] as String - val signature = list[5] as String - return FlutterPrepUploadRequest( - partnerParams, - callbackUrl, - allowNewEnroll, - partnerId, - timestamp, - signature, - ) - } - } - fun toList(): List = listOf( - partnerParams.toList(), - callbackUrl, - allowNewEnroll, - partnerId, - timestamp, - signature, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterPrepUploadResponse( - val code: String, - val refId: String, - val uploadUrl: String, - val smileJobId: String, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterPrepUploadResponse { - val code = list[0] as String - val refId = list[1] as String - val uploadUrl = list[2] as String - val smileJobId = list[3] as String - return FlutterPrepUploadResponse(code, refId, uploadUrl, smileJobId) - } - } - fun toList(): List = listOf( - code, - refId, - uploadUrl, - smileJobId, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterUploadRequest( - val images: List, - val idInfo: FlutterIdInfo? = null, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterUploadRequest { - val images = list[0] as List - val idInfo: FlutterIdInfo? = (list[1] as List?)?.let { - FlutterIdInfo.fromList(it) - } - return FlutterUploadRequest(images, idInfo) - } - } - fun toList(): List = listOf( - images, - idInfo?.toList(), - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterUploadImageInfo(val imageTypeId: FlutterImageType, val imageName: String) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterUploadImageInfo { - val imageTypeId = FlutterImageType.ofRaw(list[0] as Int)!! - val imageName = list[1] as String - return FlutterUploadImageInfo(imageTypeId, imageName) - } - } - fun toList(): List = listOf( - imageTypeId.raw, - imageName, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterIdInfo( - val country: String, - val idType: String? = null, - val idNumber: String? = null, - val firstName: String? = null, - val middleName: String? = null, - val lastName: String? = null, - val dob: String? = null, - val bankCode: String? = null, - val entered: Boolean? = null, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterIdInfo { - val country = list[0] as String - val idType = list[1] as String? - val idNumber = list[2] as String? - val firstName = list[3] as String? - val middleName = list[4] as String? - val lastName = list[5] as String? - val dob = list[6] as String? - val bankCode = list[7] as String? - val entered = list[8] as Boolean? - return FlutterIdInfo(country, idType, idNumber, firstName, middleName, lastName, dob, bankCode, entered) - } - } - fun toList(): List = listOf( - country, - idType, - idNumber, - firstName, - middleName, - lastName, - dob, - bankCode, - entered, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterEnhancedKycResponse( - val smileJobId: String, - val partnerParams: FlutterPartnerParams, - val resultText: String, - val resultCode: String, - val actions: FlutterActions, - val country: String, - val idType: String, - val idNumber: String, - val fullName: String? = null, - val expirationDate: String? = null, - val dob: String? = null, - val base64Photo: String? = null, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterEnhancedKycResponse { - val smileJobId = list[0] as String - val partnerParams = FlutterPartnerParams.fromList(list[1] as List) - val resultText = list[2] as String - val resultCode = list[3] as String - val actions = FlutterActions.fromList(list[4] as List) - val country = list[5] as String - val idType = list[6] as String - val idNumber = list[7] as String - val fullName = list[8] as String? - val expirationDate = list[9] as String? - val dob = list[10] as String? - val base64Photo = list[11] as String? - return FlutterEnhancedKycResponse(smileJobId, partnerParams, resultText, resultCode, actions, country, idType, idNumber, fullName, expirationDate, dob, base64Photo) - } - } - fun toList(): List = listOf( - smileJobId, - partnerParams.toList(), - resultText, - resultCode, - actions.toList(), - country, - idType, - idNumber, - fullName, - expirationDate, - dob, - base64Photo, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterActions( - val documentCheck: FlutterActionResult, - val humanReviewCompare: FlutterActionResult, - val humanReviewDocumentCheck: FlutterActionResult, - val humanReviewLivenessCheck: FlutterActionResult, - val humanReviewSelfieCheck: FlutterActionResult, - val humanReviewUpdateSelfie: FlutterActionResult, - val livenessCheck: FlutterActionResult, - val registerSelfie: FlutterActionResult, - val returnPersonalInfo: FlutterActionResult, - val selfieCheck: FlutterActionResult, - val selfieProvided: FlutterActionResult, - val selfieToIdAuthorityCompare: FlutterActionResult, - val selfieToIdCardCompare: FlutterActionResult, - val selfieToRegisteredSelfieCompare: FlutterActionResult, - val updateRegisteredSelfieOnFile: FlutterActionResult, - val verifyDocument: FlutterActionResult, - val verifyIdNumber: FlutterActionResult, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterActions { - val documentCheck = FlutterActionResult.ofRaw(list[0] as Int)!! - val humanReviewCompare = FlutterActionResult.ofRaw(list[1] as Int)!! - val humanReviewDocumentCheck = FlutterActionResult.ofRaw(list[2] as Int)!! - val humanReviewLivenessCheck = FlutterActionResult.ofRaw(list[3] as Int)!! - val humanReviewSelfieCheck = FlutterActionResult.ofRaw(list[4] as Int)!! - val humanReviewUpdateSelfie = FlutterActionResult.ofRaw(list[5] as Int)!! - val livenessCheck = FlutterActionResult.ofRaw(list[6] as Int)!! - val registerSelfie = FlutterActionResult.ofRaw(list[7] as Int)!! - val returnPersonalInfo = FlutterActionResult.ofRaw(list[8] as Int)!! - val selfieCheck = FlutterActionResult.ofRaw(list[9] as Int)!! - val selfieProvided = FlutterActionResult.ofRaw(list[10] as Int)!! - val selfieToIdAuthorityCompare = FlutterActionResult.ofRaw(list[11] as Int)!! - val selfieToIdCardCompare = FlutterActionResult.ofRaw(list[12] as Int)!! - val selfieToRegisteredSelfieCompare = FlutterActionResult.ofRaw(list[13] as Int)!! - val updateRegisteredSelfieOnFile = FlutterActionResult.ofRaw(list[14] as Int)!! - val verifyDocument = FlutterActionResult.ofRaw(list[15] as Int)!! - val verifyIdNumber = FlutterActionResult.ofRaw(list[16] as Int)!! - return FlutterActions(documentCheck, humanReviewCompare, humanReviewDocumentCheck, humanReviewLivenessCheck, humanReviewSelfieCheck, humanReviewUpdateSelfie, livenessCheck, registerSelfie, returnPersonalInfo, selfieCheck, selfieProvided, selfieToIdAuthorityCompare, selfieToIdCardCompare, selfieToRegisteredSelfieCompare, updateRegisteredSelfieOnFile, verifyDocument, verifyIdNumber) - } - } - fun toList(): List = listOf( - documentCheck.raw, - humanReviewCompare.raw, - humanReviewDocumentCheck.raw, - humanReviewLivenessCheck.raw, - humanReviewSelfieCheck.raw, - humanReviewUpdateSelfie.raw, - livenessCheck.raw, - registerSelfie.raw, - returnPersonalInfo.raw, - selfieCheck.raw, - selfieProvided.raw, - selfieToIdAuthorityCompare.raw, - selfieToIdCardCompare.raw, - selfieToRegisteredSelfieCompare.raw, - updateRegisteredSelfieOnFile.raw, - verifyDocument.raw, - verifyIdNumber.raw, - ) -} - -/** - * [canAccess] Whether or not the ID type is enabled for the partner - * [consentRequired] Whether or not consent is required for the ID type - * - * Generated class from Pigeon that represents data sent in messages. - */ -data class FlutterConsentInfo(val canAccess: Boolean, val consentRequired: Boolean) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterConsentInfo { - val canAccess = list[0] as Boolean - val consentRequired = list[1] as Boolean - return FlutterConsentInfo(canAccess, consentRequired) - } - } - fun toList(): List = listOf( - canAccess, - consentRequired, - ) -} - -/** - * [timestamp] is *not* a [DateTime] because technically, any arbitrary value could have been - * passed to it. This applies to all other timestamp fields in the SDK. - * - * Generated class from Pigeon that represents data sent in messages. - */ -data class FlutterEnhancedKycRequest( - val country: String, - val idType: String, - val idNumber: String, - val firstName: String? = null, - val middleName: String? = null, - val lastName: String? = null, - val dob: String? = null, - val phoneNumber: String? = null, - val bankCode: String? = null, - val callbackUrl: String? = null, - val partnerParams: FlutterPartnerParams, - val timestamp: String, - val signature: String, - val consentInformation: FlutterConsentInformation? = null, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterEnhancedKycRequest { - val country = list[0] as String - val idType = list[1] as String - val idNumber = list[2] as String - val firstName = list[3] as String? - val middleName = list[4] as String? - val lastName = list[5] as String? - val dob = list[6] as String? - val phoneNumber = list[7] as String? - val bankCode = list[8] as String? - val callbackUrl = list[9] as String? - val partnerParams = FlutterPartnerParams.fromList(list[10] as List) - val timestamp = list[11] as String - val signature = list[12] as String - val consentInformation: FlutterConsentInformation? = (list[13] as List?)?.let { - FlutterConsentInformation.fromList(it) - } - return FlutterEnhancedKycRequest(country, idType, idNumber, firstName, middleName, lastName, dob, phoneNumber, bankCode, callbackUrl, partnerParams, timestamp, signature, consentInformation) - } - } - fun toList(): List = listOf( - country, - idType, - idNumber, - firstName, - middleName, - lastName, - dob, - phoneNumber, - bankCode, - callbackUrl, - partnerParams.toList(), - timestamp, - signature, - consentInformation?.toList(), - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterEnhancedKycAsyncResponse(val success: Boolean) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterEnhancedKycAsyncResponse { - val success = list[0] as Boolean - return FlutterEnhancedKycAsyncResponse(success) - } - } - fun toList(): List = listOf( - success, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterImageLinks(val selfieImageUrl: String? = null, val error: String? = null) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterImageLinks { - val selfieImageUrl = list[0] as String? - val error = list[1] as String? - return FlutterImageLinks(selfieImageUrl, error) - } - } - fun toList(): List = listOf( - selfieImageUrl, - error, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterAntifraud(val suspectUsers: List) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterAntifraud { - val suspectUsers = list[0] as List - return FlutterAntifraud(suspectUsers) - } - } - fun toList(): List = listOf( - suspectUsers, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterSuspectUser(val reason: String, val userId: String) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterSuspectUser { - val reason = list[0] as String - val userId = list[1] as String - return FlutterSuspectUser(reason, userId) - } - } - fun toList(): List = listOf( - reason, - userId, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterJobStatusRequest( - val userId: String, - val jobId: String, - val includeImageLinks: Boolean, - val includeHistory: Boolean, - val partnerId: String, - val timestamp: String, - val signature: String, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterJobStatusRequest { - val userId = list[0] as String - val jobId = list[1] as String - val includeImageLinks = list[2] as Boolean - val includeHistory = list[3] as Boolean - val partnerId = list[4] as String - val timestamp = list[5] as String - val signature = list[6] as String - return FlutterJobStatusRequest( - userId, - jobId, - includeImageLinks, - includeHistory, - partnerId, - timestamp, - signature, - ) - } - } - fun toList(): List = listOf( - userId, - jobId, - includeImageLinks, - includeHistory, - partnerId, - timestamp, - signature, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterSmartSelfieJobResult( - val actions: FlutterActions, - val resultCode: String, - val resultText: String, - val smileJobId: String, - val partnerParams: FlutterPartnerParams, - val confidence: Double? = null, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterSmartSelfieJobResult { - val actions = FlutterActions.fromList(list[0] as List) - val resultCode = list[1] as String - val resultText = list[2] as String - val smileJobId = list[3] as String - val partnerParams = FlutterPartnerParams.fromList(list[4] as List) - val confidence = list[5] as Double? - return FlutterSmartSelfieJobResult( - actions, - resultCode, - resultText, - smileJobId, - partnerParams, - confidence, - ) - } - } - fun toList(): List = listOf( - actions.toList(), - resultCode, - resultText, - smileJobId, - partnerParams.toList(), - confidence, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterSmartSelfieJobStatusResponse( - val timestamp: String, - val jobComplete: Boolean, - val jobSuccess: Boolean, - val code: String, - val result: FlutterSmartSelfieJobResult? = null, - val resultString: String? = null, - val history: List? = null, - val imageLinks: FlutterImageLinks? = null, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterSmartSelfieJobStatusResponse { - val timestamp = list[0] as String - val jobComplete = list[1] as Boolean - val jobSuccess = list[2] as Boolean - val code = list[3] as String - val result: FlutterSmartSelfieJobResult? = (list[4] as List?)?.let { - FlutterSmartSelfieJobResult.fromList(it) - } - val resultString = list[5] as String? - val history = list[6] as List? - val imageLinks: FlutterImageLinks? = (list[7] as List?)?.let { - FlutterImageLinks.fromList(it) - } - return FlutterSmartSelfieJobStatusResponse( - timestamp, - jobComplete, - jobSuccess, - code, - result, - resultString, - history, - imageLinks, - ) - } - } - fun toList(): List = listOf( - timestamp, - jobComplete, - jobSuccess, - code, - result?.toList(), - resultString, - history, - imageLinks?.toList(), - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterSmartSelfieResponse( - val code: String, - val createdAt: String, - val jobId: String, - val jobType: FlutterJobTypeV2, - val message: String, - val partnerId: String, - val partnerParams: Map? = null, - val status: FlutterSmartSelfieStatus, - val updatedAt: String, - val userId: String, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterSmartSelfieResponse { - val code = list[0] as String - val createdAt = list[1] as String - val jobId = list[2] as String - val jobType = FlutterJobTypeV2.ofRaw(list[3] as Int)!! - val message = list[4] as String - val partnerId = list[5] as String - val partnerParams = list[6] as Map? - val status = FlutterSmartSelfieStatus.ofRaw(list[7] as Int)!! - val updatedAt = list[8] as String - val userId = list[9] as String - return FlutterSmartSelfieResponse(code, createdAt, jobId, jobType, message, partnerId, partnerParams, status, updatedAt, userId) - } - } - fun toList(): List = listOf( - code, - createdAt, - jobId, - jobType.raw, - message, - partnerId, - partnerParams, - status.raw, - updatedAt, - userId, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterDocumentVerificationJobResult( - val actions: FlutterActions, - val resultCode: String, - val resultText: String, - val smileJobId: String, - val partnerParams: FlutterPartnerParams, - val country: String? = null, - val idType: String? = null, - val idNumber: String? = null, - val fullName: String? = null, - val dob: String? = null, - val gender: String? = null, - val expirationDate: String? = null, - val documentImageBase64: String? = null, - val phoneNumber: String? = null, - val phoneNumber2: String? = null, - val address: String? = null, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterDocumentVerificationJobResult { - val actions = FlutterActions.fromList(list[0] as List) - val resultCode = list[1] as String - val resultText = list[2] as String - val smileJobId = list[3] as String - val partnerParams = FlutterPartnerParams.fromList(list[4] as List) - val country = list[5] as String? - val idType = list[6] as String? - val idNumber = list[7] as String? - val fullName = list[8] as String? - val dob = list[9] as String? - val gender = list[10] as String? - val expirationDate = list[11] as String? - val documentImageBase64 = list[12] as String? - val phoneNumber = list[13] as String? - val phoneNumber2 = list[14] as String? - val address = list[15] as String? - return FlutterDocumentVerificationJobResult(actions, resultCode, resultText, smileJobId, partnerParams, country, idType, idNumber, fullName, dob, gender, expirationDate, documentImageBase64, phoneNumber, phoneNumber2, address) - } - } - fun toList(): List = listOf( - actions.toList(), - resultCode, - resultText, - smileJobId, - partnerParams.toList(), - country, - idType, - idNumber, - fullName, - dob, - gender, - expirationDate, - documentImageBase64, - phoneNumber, - phoneNumber2, - address, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterDocumentVerificationJobStatusResponse( - val timestamp: String, - val jobComplete: Boolean, - val jobSuccess: Boolean, - val code: String, - val result: FlutterDocumentVerificationJobResult? = null, - val resultString: String? = null, - val history: List? = null, - val imageLinks: FlutterImageLinks? = null, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterDocumentVerificationJobStatusResponse { - val timestamp = list[0] as String - val jobComplete = list[1] as Boolean - val jobSuccess = list[2] as Boolean - val code = list[3] as String - val result: FlutterDocumentVerificationJobResult? = (list[4] as List?)?.let { - FlutterDocumentVerificationJobResult.fromList(it) - } - val resultString = list[5] as String? - val history = list[6] as List? - val imageLinks: FlutterImageLinks? = (list[7] as List?)?.let { - FlutterImageLinks.fromList(it) - } - return FlutterDocumentVerificationJobStatusResponse( - timestamp, - jobComplete, - jobSuccess, - code, - result, - resultString, - history, - imageLinks, - ) - } - } - fun toList(): List = listOf( - timestamp, - jobComplete, - jobSuccess, - code, - result?.toList(), - resultString, - history, - imageLinks?.toList(), - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterBiometricKycJobResult( - val actions: FlutterActions, - val resultCode: String, - val resultText: String, - val resultType: String, - val smileJobId: String, - val partnerParams: FlutterPartnerParams, - val antifraud: FlutterAntifraud? = null, - val dob: String? = null, - val photoBase64: String? = null, - val gender: String? = null, - val idType: String? = null, - val address: String? = null, - val country: String? = null, - val documentImageBase64: String? = null, - val fullData: Map? = null, - val fullName: String? = null, - val idNumber: String? = null, - val phoneNumber: String? = null, - val phoneNumber2: String? = null, - val expirationDate: String? = null, - val secondaryIdNumber: String? = null, - val idNumberPreviouslyRegistered: Boolean? = null, - val previousRegistrantsUserIds: List? = null, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterBiometricKycJobResult { - val actions = FlutterActions.fromList(list[0] as List) - val resultCode = list[1] as String - val resultText = list[2] as String - val resultType = list[3] as String - val smileJobId = list[4] as String - val partnerParams = FlutterPartnerParams.fromList(list[5] as List) - val antifraud: FlutterAntifraud? = (list[6] as List?)?.let { - FlutterAntifraud.fromList(it) - } - val dob = list[7] as String? - val photoBase64 = list[8] as String? - val gender = list[9] as String? - val idType = list[10] as String? - val address = list[11] as String? - val country = list[12] as String? - val documentImageBase64 = list[13] as String? - val fullData = list[14] as Map? - val fullName = list[15] as String? - val idNumber = list[16] as String? - val phoneNumber = list[17] as String? - val phoneNumber2 = list[18] as String? - val expirationDate = list[19] as String? - val secondaryIdNumber = list[20] as String? - val idNumberPreviouslyRegistered = list[21] as Boolean? - val previousRegistrantsUserIds = list[22] as List? - return FlutterBiometricKycJobResult(actions, resultCode, resultText, resultType, smileJobId, partnerParams, antifraud, dob, photoBase64, gender, idType, address, country, documentImageBase64, fullData, fullName, idNumber, phoneNumber, phoneNumber2, expirationDate, secondaryIdNumber, idNumberPreviouslyRegistered, previousRegistrantsUserIds) - } - } - fun toList(): List = listOf( - actions.toList(), - resultCode, - resultText, - resultType, - smileJobId, - partnerParams.toList(), - antifraud?.toList(), - dob, - photoBase64, - gender, - idType, - address, - country, - documentImageBase64, - fullData, - fullName, - idNumber, - phoneNumber, - phoneNumber2, - expirationDate, - secondaryIdNumber, - idNumberPreviouslyRegistered, - previousRegistrantsUserIds, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterBiometricKycJobStatusResponse( - val timestamp: String, - val jobComplete: Boolean, - val jobSuccess: Boolean, - val code: String, - val result: FlutterBiometricKycJobResult? = null, - val resultString: String? = null, - val history: List? = null, - val imageLinks: FlutterImageLinks? = null, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterBiometricKycJobStatusResponse { - val timestamp = list[0] as String - val jobComplete = list[1] as Boolean - val jobSuccess = list[2] as Boolean - val code = list[3] as String - val result: FlutterBiometricKycJobResult? = (list[4] as List?)?.let { - FlutterBiometricKycJobResult.fromList(it) - } - val resultString = list[5] as String? - val history = list[6] as List? - val imageLinks: FlutterImageLinks? = (list[7] as List?)?.let { - FlutterImageLinks.fromList(it) - } - return FlutterBiometricKycJobStatusResponse( - timestamp, - jobComplete, - jobSuccess, - code, - result, - resultString, - history, - imageLinks, - ) - } - } - fun toList(): List = listOf( - timestamp, - jobComplete, - jobSuccess, - code, - result?.toList(), - resultString, - history, - imageLinks?.toList(), - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterEnhancedDocumentVerificationJobResult( - val actions: FlutterActions, - val resultCode: String, - val resultText: String, - val resultType: String, - val smileJobId: String, - val partnerParams: FlutterPartnerParams, - val antifraud: FlutterAntifraud? = null, - val dob: String? = null, - val photoBase64: String? = null, - val gender: String? = null, - val idType: String? = null, - val address: String? = null, - val country: String? = null, - val documentImageBase64: String? = null, - val fullData: Map? = null, - val fullName: String? = null, - val idNumber: String? = null, - val phoneNumber: String? = null, - val phoneNumber2: String? = null, - val expirationDate: String? = null, - val secondaryIdNumber: String? = null, - val idNumberPreviouslyRegistered: Boolean? = null, - val previousRegistrantsUserIds: List? = null, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterEnhancedDocumentVerificationJobResult { - val actions = FlutterActions.fromList(list[0] as List) - val resultCode = list[1] as String - val resultText = list[2] as String - val resultType = list[3] as String - val smileJobId = list[4] as String - val partnerParams = FlutterPartnerParams.fromList(list[5] as List) - val antifraud: FlutterAntifraud? = (list[6] as List?)?.let { - FlutterAntifraud.fromList(it) - } - val dob = list[7] as String? - val photoBase64 = list[8] as String? - val gender = list[9] as String? - val idType = list[10] as String? - val address = list[11] as String? - val country = list[12] as String? - val documentImageBase64 = list[13] as String? - val fullData = list[14] as Map? - val fullName = list[15] as String? - val idNumber = list[16] as String? - val phoneNumber = list[17] as String? - val phoneNumber2 = list[18] as String? - val expirationDate = list[19] as String? - val secondaryIdNumber = list[20] as String? - val idNumberPreviouslyRegistered = list[21] as Boolean? - val previousRegistrantsUserIds = list[22] as List? - return FlutterEnhancedDocumentVerificationJobResult(actions, resultCode, resultText, resultType, smileJobId, partnerParams, antifraud, dob, photoBase64, gender, idType, address, country, documentImageBase64, fullData, fullName, idNumber, phoneNumber, phoneNumber2, expirationDate, secondaryIdNumber, idNumberPreviouslyRegistered, previousRegistrantsUserIds) - } - } - fun toList(): List = listOf( - actions.toList(), - resultCode, - resultText, - resultType, - smileJobId, - partnerParams.toList(), - antifraud?.toList(), - dob, - photoBase64, - gender, - idType, - address, - country, - documentImageBase64, - fullData, - fullName, - idNumber, - phoneNumber, - phoneNumber2, - expirationDate, - secondaryIdNumber, - idNumberPreviouslyRegistered, - previousRegistrantsUserIds, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterEnhancedDocumentVerificationJobStatusResponse( - val timestamp: String, - val jobComplete: Boolean, - val jobSuccess: Boolean, - val code: String, - val result: FlutterEnhancedDocumentVerificationJobResult? = null, - val resultString: String? = null, - val history: List? = null, - val imageLinks: FlutterImageLinks? = null, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterEnhancedDocumentVerificationJobStatusResponse { - val timestamp = list[0] as String - val jobComplete = list[1] as Boolean - val jobSuccess = list[2] as Boolean - val code = list[3] as String - val result: FlutterEnhancedDocumentVerificationJobResult? = (list[4] as List?)?.let { - FlutterEnhancedDocumentVerificationJobResult.fromList(it) - } - val resultString = list[5] as String? - val history = list[6] as List? - val imageLinks: FlutterImageLinks? = (list[7] as List?)?.let { - FlutterImageLinks.fromList(it) - } - return FlutterEnhancedDocumentVerificationJobStatusResponse( - timestamp, - jobComplete, - jobSuccess, - code, - result, - resultString, - history, - imageLinks, - ) - } - } - fun toList(): List = listOf( - timestamp, - jobComplete, - jobSuccess, - code, - result?.toList(), - resultString, - history, - imageLinks?.toList(), - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterProductsConfigRequest( - val partnerId: String, - val timestamp: String, - val signature: String, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterProductsConfigRequest { - val partnerId = list[0] as String - val timestamp = list[1] as String - val signature = list[2] as String - return FlutterProductsConfigRequest(partnerId, timestamp, signature) - } - } - fun toList(): List = listOf( - partnerId, - timestamp, - signature, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterProductsConfigResponse( - val consentRequired: Map?>, - val idSelection: FlutterIdSelection, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterProductsConfigResponse { - val consentRequired = list[0] as Map?> - val idSelection = FlutterIdSelection.fromList(list[1] as List) - return FlutterProductsConfigResponse(consentRequired, idSelection) - } - } - fun toList(): List = listOf( - consentRequired, - idSelection.toList(), - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterIdSelection( - val basicKyc: Map?>, - val biometricKyc: Map?>, - val enhancedKyc: Map?>, - val documentVerification: Map?>, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterIdSelection { - val basicKyc = list[0] as Map?> - val biometricKyc = list[1] as Map?> - val enhancedKyc = list[2] as Map?> - val documentVerification = list[3] as Map?> - return FlutterIdSelection(basicKyc, biometricKyc, enhancedKyc, documentVerification) - } - } - fun toList(): List = listOf( - basicKyc, - biometricKyc, - enhancedKyc, - documentVerification, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterValidDocumentsResponse(val validDocuments: List) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterValidDocumentsResponse { - val validDocuments = list[0] as List - return FlutterValidDocumentsResponse(validDocuments) - } - } - fun toList(): List = listOf( - validDocuments, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterValidDocument(val country: FlutterCountry, val idTypes: List) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterValidDocument { - val country = FlutterCountry.fromList(list[0] as List) - val idTypes = list[1] as List - return FlutterValidDocument(country, idTypes) - } - } - fun toList(): List = listOf( - country.toList(), - idTypes, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterCountry(val code: String, val continent: String, val name: String) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterCountry { - val code = list[0] as String - val continent = list[1] as String - val name = list[2] as String - return FlutterCountry(code, continent, name) - } - } - fun toList(): List = listOf( - code, - continent, - name, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterIdType( - val code: String, - val example: List, - val hasBack: Boolean, - val name: String, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterIdType { - val code = list[0] as String - val example = list[1] as List - val hasBack = list[2] as Boolean - val name = list[3] as String - return FlutterIdType(code, example, hasBack, name) - } - } - fun toList(): List = listOf( - code, - example, - hasBack, - name, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterServicesResponse( - val bankCodes: List, - val hostedWeb: FlutterHostedWeb, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterServicesResponse { - val bankCodes = list[0] as List - val hostedWeb = FlutterHostedWeb.fromList(list[1] as List) - return FlutterServicesResponse(bankCodes, hostedWeb) - } - } - fun toList(): List = listOf( - bankCodes, - hostedWeb.toList(), - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterBankCode(val name: String, val code: String) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterBankCode { - val name = list[0] as String - val code = list[1] as String - return FlutterBankCode(name, code) - } - } - fun toList(): List = listOf( - name, - code, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterHostedWeb( - val basicKyc: Map, - val biometricKyc: Map, - val enhancedKyc: Map, - val documentVerification: Map, - val enhancedKycSmartSelfie: Map, - val enhancedDocumentVerification: Map, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterHostedWeb { - val basicKyc = list[0] as Map - val biometricKyc = list[1] as Map - val enhancedKyc = list[2] as Map - val documentVerification = list[3] as Map - val enhancedKycSmartSelfie = list[4] as Map - val enhancedDocumentVerification = list[5] as Map - return FlutterHostedWeb( - basicKyc, - biometricKyc, - enhancedKyc, - documentVerification, - enhancedKycSmartSelfie, - enhancedDocumentVerification, - ) - } - } - fun toList(): List = listOf( - basicKyc, - biometricKyc, - enhancedKyc, - documentVerification, - enhancedKycSmartSelfie, - enhancedDocumentVerification, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterCountryInfo( - val countryCode: String, - val name: String, - val availableIdTypes: List, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterCountryInfo { - val countryCode = list[0] as String - val name = list[1] as String - val availableIdTypes = list[2] as List - return FlutterCountryInfo(countryCode, name, availableIdTypes) - } - } - fun toList(): List = listOf( - countryCode, - name, - availableIdTypes, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterAvailableIdType( - val idTypeKey: String, - val label: String, - val requiredFields: List, - val testData: String? = null, - val idNumberRegex: String? = null, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterAvailableIdType { - val idTypeKey = list[0] as String - val label = list[1] as String - val requiredFields = list[2] as List - val testData = list[3] as String? - val idNumberRegex = list[4] as String? - return FlutterAvailableIdType(idTypeKey, label, requiredFields, testData, idNumberRegex) - } - } - fun toList(): List = listOf( - idTypeKey, - label, - requiredFields, - testData, - idNumberRegex, - ) -} - -/** Generated class from Pigeon that represents data sent in messages. */ -data class FlutterConfig( - val partnerId: String, - val authToken: String, - val prodBaseUrl: String, - val sandboxBaseUrl: String, - -) { - companion object { - @Suppress("UNCHECKED_CAST") - fun fromList(list: List): FlutterConfig { - val partnerId = list[0] as String - val authToken = list[1] as String - val prodBaseUrl = list[2] as String - val sandboxBaseUrl = list[3] as String - return FlutterConfig(partnerId, authToken, prodBaseUrl, sandboxBaseUrl) - } - } - fun toList(): List = listOf( - partnerId, - authToken, - prodBaseUrl, - sandboxBaseUrl, - ) -} - -@Suppress("UNCHECKED_CAST") -private object SmileIDApiCodec : StandardMessageCodec() { - override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { - return when (type) { - 128.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterActions.fromList(it) - } - } - 129.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterAntifraud.fromList(it) - } - } - 130.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterAuthenticationRequest.fromList(it) - } - } - 131.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterAuthenticationResponse.fromList(it) - } - } - 132.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterAvailableIdType.fromList(it) - } - } - 133.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterBankCode.fromList(it) - } - } - 134.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterBiometricKycJobResult.fromList(it) - } - } - 135.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterBiometricKycJobResult.fromList(it) - } - } - 136.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterBiometricKycJobStatusResponse.fromList(it) - } - } - 137.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterConfig.fromList(it) - } - } - 138.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterConsentInfo.fromList(it) - } - } - 139.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterConsentInformation.fromList(it) - } - } - 140.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterCountry.fromList(it) - } - } - 141.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterCountryInfo.fromList(it) - } - } - 142.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterDocumentVerificationJobResult.fromList(it) - } - } - 143.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterDocumentVerificationJobResult.fromList(it) - } - } - 144.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterDocumentVerificationJobStatusResponse.fromList(it) - } - } - 145.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterEnhancedDocumentVerificationJobResult.fromList(it) - } - } - 146.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterEnhancedDocumentVerificationJobResult.fromList(it) - } - } - 147.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterEnhancedDocumentVerificationJobStatusResponse.fromList(it) - } - } - 148.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterEnhancedKycAsyncResponse.fromList(it) - } - } - 149.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterEnhancedKycRequest.fromList(it) - } - } - 150.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterEnhancedKycResponse.fromList(it) - } - } - 151.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterHostedWeb.fromList(it) - } - } - 152.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterIdInfo.fromList(it) - } - } - 153.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterIdSelection.fromList(it) - } - } - 154.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterIdType.fromList(it) - } - } - 155.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterImageLinks.fromList(it) - } - } - 156.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterJobStatusRequest.fromList(it) - } - } - 157.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterPartnerParams.fromList(it) - } - } - 158.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterPrepUploadRequest.fromList(it) - } - } - 159.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterPrepUploadResponse.fromList(it) - } - } - 160.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterProductsConfigRequest.fromList(it) - } - } - 161.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterProductsConfigResponse.fromList(it) - } - } - 162.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterServicesResponse.fromList(it) - } - } - 163.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterSmartSelfieJobResult.fromList(it) - } - } - 164.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterSmartSelfieJobResult.fromList(it) - } - } - 165.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterSmartSelfieJobStatusResponse.fromList(it) - } - } - 166.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterSmartSelfieResponse.fromList(it) - } - } - 167.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterSuspectUser.fromList(it) - } - } - 168.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterUploadImageInfo.fromList(it) - } - } - 169.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterUploadRequest.fromList(it) - } - } - 170.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterValidDocument.fromList(it) - } - } - 171.toByte() -> { - return (readValue(buffer) as? List)?.let { - FlutterValidDocumentsResponse.fromList(it) - } - } - else -> super.readValueOfType(type, buffer) - } - } - override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { - when (value) { - is FlutterActions -> { - stream.write(128) - writeValue(stream, value.toList()) - } - is FlutterAntifraud -> { - stream.write(129) - writeValue(stream, value.toList()) - } - is FlutterAuthenticationRequest -> { - stream.write(130) - writeValue(stream, value.toList()) - } - is FlutterAuthenticationResponse -> { - stream.write(131) - writeValue(stream, value.toList()) - } - is FlutterAvailableIdType -> { - stream.write(132) - writeValue(stream, value.toList()) - } - is FlutterBankCode -> { - stream.write(133) - writeValue(stream, value.toList()) - } - is FlutterBiometricKycJobResult -> { - stream.write(134) - writeValue(stream, value.toList()) - } - is FlutterBiometricKycJobResult -> { - stream.write(135) - writeValue(stream, value.toList()) - } - is FlutterBiometricKycJobStatusResponse -> { - stream.write(136) - writeValue(stream, value.toList()) - } - is FlutterConfig -> { - stream.write(137) - writeValue(stream, value.toList()) - } - is FlutterConsentInfo -> { - stream.write(138) - writeValue(stream, value.toList()) - } - is FlutterConsentInformation -> { - stream.write(139) - writeValue(stream, value.toList()) - } - is FlutterCountry -> { - stream.write(140) - writeValue(stream, value.toList()) - } - is FlutterCountryInfo -> { - stream.write(141) - writeValue(stream, value.toList()) - } - is FlutterDocumentVerificationJobResult -> { - stream.write(142) - writeValue(stream, value.toList()) - } - is FlutterDocumentVerificationJobResult -> { - stream.write(143) - writeValue(stream, value.toList()) - } - is FlutterDocumentVerificationJobStatusResponse -> { - stream.write(144) - writeValue(stream, value.toList()) - } - is FlutterEnhancedDocumentVerificationJobResult -> { - stream.write(145) - writeValue(stream, value.toList()) - } - is FlutterEnhancedDocumentVerificationJobResult -> { - stream.write(146) - writeValue(stream, value.toList()) - } - is FlutterEnhancedDocumentVerificationJobStatusResponse -> { - stream.write(147) - writeValue(stream, value.toList()) - } - is FlutterEnhancedKycAsyncResponse -> { - stream.write(148) - writeValue(stream, value.toList()) - } - is FlutterEnhancedKycRequest -> { - stream.write(149) - writeValue(stream, value.toList()) - } - is FlutterEnhancedKycResponse -> { - stream.write(150) - writeValue(stream, value.toList()) - } - is FlutterHostedWeb -> { - stream.write(151) - writeValue(stream, value.toList()) - } - is FlutterIdInfo -> { - stream.write(152) - writeValue(stream, value.toList()) - } - is FlutterIdSelection -> { - stream.write(153) - writeValue(stream, value.toList()) - } - is FlutterIdType -> { - stream.write(154) - writeValue(stream, value.toList()) - } - is FlutterImageLinks -> { - stream.write(155) - writeValue(stream, value.toList()) - } - is FlutterJobStatusRequest -> { - stream.write(156) - writeValue(stream, value.toList()) - } - is FlutterPartnerParams -> { - stream.write(157) - writeValue(stream, value.toList()) - } - is FlutterPrepUploadRequest -> { - stream.write(158) - writeValue(stream, value.toList()) - } - is FlutterPrepUploadResponse -> { - stream.write(159) - writeValue(stream, value.toList()) - } - is FlutterProductsConfigRequest -> { - stream.write(160) - writeValue(stream, value.toList()) - } - is FlutterProductsConfigResponse -> { - stream.write(161) - writeValue(stream, value.toList()) - } - is FlutterServicesResponse -> { - stream.write(162) - writeValue(stream, value.toList()) - } - is FlutterSmartSelfieJobResult -> { - stream.write(163) - writeValue(stream, value.toList()) - } - is FlutterSmartSelfieJobResult -> { - stream.write(164) - writeValue(stream, value.toList()) - } - is FlutterSmartSelfieJobStatusResponse -> { - stream.write(165) - writeValue(stream, value.toList()) - } - is FlutterSmartSelfieResponse -> { - stream.write(166) - writeValue(stream, value.toList()) - } - is FlutterSuspectUser -> { - stream.write(167) - writeValue(stream, value.toList()) - } - is FlutterUploadImageInfo -> { - stream.write(168) - writeValue(stream, value.toList()) - } - is FlutterUploadRequest -> { - stream.write(169) - writeValue(stream, value.toList()) - } - is FlutterValidDocument -> { - stream.write(170) - writeValue(stream, value.toList()) - } - is FlutterValidDocumentsResponse -> { - stream.write(171) - writeValue(stream, value.toList()) - } - else -> super.writeValue(stream, value) - } - } -} - -/** Generated interface from Pigeon that represents a handler of messages from Flutter. */ -interface SmileIDApi { - fun initializeWithApiKey( - apiKey: String, - config: FlutterConfig, - useSandbox: Boolean, - enableCrashReporting: Boolean, - ) - fun initializeWithConfig( - config: FlutterConfig, - useSandbox: Boolean, - enableCrashReporting: Boolean, - ) - fun initialize(useSandbox: Boolean) - fun setCallbackUrl(callbackUrl: String) - fun setAllowOfflineMode(allowOfflineMode: Boolean) - fun getSubmittedJobs(): List - fun getUnsubmittedJobs(): List - fun cleanup(jobId: String) - fun cleanupJobs(jobIds: List) - fun submitJob(jobId: String, deleteFilesOnSuccess: Boolean) - fun authenticate( - request: FlutterAuthenticationRequest, - callback: (Result) -> Unit, - ) - fun prepUpload( - request: FlutterPrepUploadRequest, - callback: (Result) -> Unit, - ) - fun upload(url: String, request: FlutterUploadRequest, callback: (Result) -> Unit) - fun doEnhancedKyc( - request: FlutterEnhancedKycRequest, - callback: (Result) -> Unit, - ) - fun doEnhancedKycAsync( - request: FlutterEnhancedKycRequest, - callback: (Result) -> Unit, - ) - fun getSmartSelfieJobStatus( - request: FlutterJobStatusRequest, - callback: (Result) -> Unit, - ) - fun doSmartSelfieEnrollment( - signature: String, - timestamp: String, - selfieImage: String, - livenessImages: List, - userId: String, - partnerParams: Map?, - callbackUrl: String?, - sandboxResult: Long?, - allowNewEnroll: Boolean?, - callback: (Result) -> Unit, - ) - fun doSmartSelfieAuthentication( - signature: String, - timestamp: String, - selfieImage: String, - livenessImages: List, - userId: String, - partnerParams: Map?, - callbackUrl: String?, - sandboxResult: Long?, - callback: (Result) -> Unit, - ) - fun getDocumentVerificationJobStatus( - request: FlutterJobStatusRequest, - callback: (Result) -> Unit, - ) - fun getBiometricKycJobStatus( - request: FlutterJobStatusRequest, - callback: (Result) -> Unit, - ) - fun getEnhancedDocumentVerificationJobStatus( - request: FlutterJobStatusRequest, - callback: (Result) -> Unit, - ) - fun getProductsConfig( - request: FlutterProductsConfigRequest, - callback: (Result) -> Unit, - ) - fun getValidDocuments( - request: FlutterProductsConfigRequest, - callback: (Result) -> Unit, - ) - fun getServices(callback: (Result) -> Unit) - fun pollSmartSelfieJobStatus( - request: FlutterJobStatusRequest, - interval: Long, - numAttempts: Long, - callback: (Result) -> Unit, - ) - fun pollDocumentVerificationJobStatus( - request: FlutterJobStatusRequest, - interval: Long, - numAttempts: Long, - callback: (Result) -> Unit, - ) - fun pollBiometricKycJobStatus( - request: FlutterJobStatusRequest, - interval: Long, - numAttempts: Long, - callback: (Result) -> Unit, - ) - fun pollEnhancedDocumentVerificationJobStatus( - request: FlutterJobStatusRequest, - interval: Long, - numAttempts: Long, - callback: (Result) -> Unit, - ) - - companion object { - /** The codec used by SmileIDApi. */ - val codec: MessageCodec by lazy { - SmileIDApiCodec - } - - /** Sets up an instance of `SmileIDApi` to handle messages through the `binaryMessenger`. */ - @Suppress("UNCHECKED_CAST") - fun setUp(binaryMessenger: BinaryMessenger, api: SmileIDApi?) { - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.initializeWithApiKey", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val apiKeyArg = args[0] as String - val configArg = args[1] as FlutterConfig - val useSandboxArg = args[2] as Boolean - val enableCrashReportingArg = args[3] as Boolean - var wrapped: List - try { - api.initializeWithApiKey( - apiKeyArg, - configArg, - useSandboxArg, - enableCrashReportingArg, - ) - wrapped = listOf(null) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.initializeWithConfig", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val configArg = args[0] as FlutterConfig - val useSandboxArg = args[1] as Boolean - val enableCrashReportingArg = args[2] as Boolean - var wrapped: List - try { - api.initializeWithConfig( - configArg, - useSandboxArg, - enableCrashReportingArg, - ) - wrapped = listOf(null) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.initialize", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val useSandboxArg = args[0] as Boolean - var wrapped: List - try { - api.initialize(useSandboxArg) - wrapped = listOf(null) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.setCallbackUrl", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val callbackUrlArg = args[0] as String - var wrapped: List - try { - api.setCallbackUrl(callbackUrlArg) - wrapped = listOf(null) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.setAllowOfflineMode", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val allowOfflineModeArg = args[0] as Boolean - var wrapped: List - try { - api.setAllowOfflineMode(allowOfflineModeArg) - wrapped = listOf(null) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.getSubmittedJobs", - codec, - ) - if (api != null) { - channel.setMessageHandler { _, reply -> - var wrapped: List - try { - wrapped = listOf(api.getSubmittedJobs()) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.getUnsubmittedJobs", - codec, - ) - if (api != null) { - channel.setMessageHandler { _, reply -> - var wrapped: List - try { - wrapped = listOf(api.getUnsubmittedJobs()) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.cleanup", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val jobIdArg = args[0] as String - var wrapped: List - try { - api.cleanup(jobIdArg) - wrapped = listOf(null) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.cleanupJobs", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val jobIdsArg = args[0] as List - var wrapped: List - try { - api.cleanupJobs(jobIdsArg) - wrapped = listOf(null) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.submitJob", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val jobIdArg = args[0] as String - val deleteFilesOnSuccessArg = args[1] as Boolean - var wrapped: List - try { - api.submitJob(jobIdArg, deleteFilesOnSuccessArg) - wrapped = listOf(null) - } catch (exception: Throwable) { - wrapped = wrapError(exception) - } - reply.reply(wrapped) - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.authenticate", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val requestArg = args[0] as FlutterAuthenticationRequest - api.authenticate( - requestArg, - ) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.prepUpload", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val requestArg = args[0] as FlutterPrepUploadRequest - api.prepUpload(requestArg) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.upload", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val urlArg = args[0] as String - val requestArg = args[1] as FlutterUploadRequest - api.upload(urlArg, requestArg) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - reply.reply(wrapResult(null)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.doEnhancedKyc", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val requestArg = args[0] as FlutterEnhancedKycRequest - api.doEnhancedKyc( - requestArg, - ) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.doEnhancedKycAsync", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val requestArg = args[0] as FlutterEnhancedKycRequest - api.doEnhancedKycAsync( - requestArg, - ) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.getSmartSelfieJobStatus", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val requestArg = args[0] as FlutterJobStatusRequest - api.getSmartSelfieJobStatus( - requestArg, - ) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.doSmartSelfieEnrollment", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val signatureArg = args[0] as String - val timestampArg = args[1] as String - val selfieImageArg = args[2] as String - val livenessImagesArg = args[3] as List - val userIdArg = args[4] as String - val partnerParamsArg = args[5] as Map? - val callbackUrlArg = args[6] as String? - val sandboxResultArg = args[7].let { - if (it is Int) it.toLong() else it as Long? - } - val allowNewEnrollArg = args[8] as Boolean? - api.doSmartSelfieEnrollment(signatureArg, timestampArg, selfieImageArg, livenessImagesArg, userIdArg, partnerParamsArg, callbackUrlArg, sandboxResultArg, allowNewEnrollArg) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.doSmartSelfieAuthentication", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val signatureArg = args[0] as String - val timestampArg = args[1] as String - val selfieImageArg = args[2] as String - val livenessImagesArg = args[3] as List - val userIdArg = args[4] as String - val partnerParamsArg = args[5] as Map? - val callbackUrlArg = args[6] as String? - val sandboxResultArg = args[7].let { - if (it is Int) it.toLong() else it as Long? - } - api.doSmartSelfieAuthentication( - signatureArg, - timestampArg, - selfieImageArg, - livenessImagesArg, - userIdArg, - partnerParamsArg, - callbackUrlArg, - sandboxResultArg, - ) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.getDocumentVerificationJobStatus", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val requestArg = args[0] as FlutterJobStatusRequest - api.getDocumentVerificationJobStatus( - requestArg, - ) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.getBiometricKycJobStatus", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val requestArg = args[0] as FlutterJobStatusRequest - api.getBiometricKycJobStatus( - requestArg, - ) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.getEnhancedDocumentVerificationJobStatus", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val requestArg = args[0] as FlutterJobStatusRequest - api.getEnhancedDocumentVerificationJobStatus(requestArg) { - result: - Result, - -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.getProductsConfig", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val requestArg = args[0] as FlutterProductsConfigRequest - api.getProductsConfig( - requestArg, - ) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.getValidDocuments", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val requestArg = args[0] as FlutterProductsConfigRequest - api.getValidDocuments( - requestArg, - ) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.getServices", - codec, - ) - if (api != null) { - channel.setMessageHandler { _, reply -> - api.getServices { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.pollSmartSelfieJobStatus", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val requestArg = args[0] as FlutterJobStatusRequest - val intervalArg = args[1].let { if (it is Int) it.toLong() else it as Long } - val numAttemptsArg = args[2].let { - if (it is Int) it.toLong() else it as Long - } - api.pollSmartSelfieJobStatus( - requestArg, - intervalArg, - numAttemptsArg, - ) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.pollDocumentVerificationJobStatus", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val requestArg = args[0] as FlutterJobStatusRequest - val intervalArg = args[1].let { if (it is Int) it.toLong() else it as Long } - val numAttemptsArg = args[2].let { - if (it is Int) it.toLong() else it as Long - } - api.pollDocumentVerificationJobStatus( - requestArg, - intervalArg, - numAttemptsArg, - ) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.pollBiometricKycJobStatus", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val requestArg = args[0] as FlutterJobStatusRequest - val intervalArg = args[1].let { if (it is Int) it.toLong() else it as Long } - val numAttemptsArg = args[2].let { - if (it is Int) it.toLong() else it as Long - } - api.pollBiometricKycJobStatus( - requestArg, - intervalArg, - numAttemptsArg, - ) { result: Result -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - run { - val channel = - BasicMessageChannel( - binaryMessenger, - "dev.flutter.pigeon.smileid.SmileIDApi.pollEnhancedDocumentVerificationJobStatus", - codec, - ) - if (api != null) { - channel.setMessageHandler { message, reply -> - val args = message as List - val requestArg = args[0] as FlutterJobStatusRequest - val intervalArg = args[1].let { if (it is Int) it.toLong() else it as Long } - val numAttemptsArg = args[2].let { - if (it is Int) it.toLong() else it as Long - } - api.pollEnhancedDocumentVerificationJobStatus( - requestArg, - intervalArg, - numAttemptsArg, - ) { - result: - Result, - -> - val error = result.exceptionOrNull() - if (error != null) { - reply.reply(wrapError(error)) - } else { - val data = result.getOrNull() - reply.reply(wrapResult(data)) - } - } - } - } else { - channel.setMessageHandler(null) - } - } - } - } -} diff --git a/android/src/main/kotlin/com/smileidentity/flutter/results/DocumentCaptureResult.kt b/android/src/main/kotlin/com/smileidentity/flutter/results/DocumentCaptureResult.kt deleted file mode 100644 index 827befa..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/results/DocumentCaptureResult.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.smileidentity.flutter.results - -import java.io.File - -data class DocumentCaptureResult( - val selfieFile: File? = null, - val documentFrontFile: File? = null, - val livenessFiles: List? = null, - val documentBackFile: File? = null, - val didSubmitDocumentVerificationJob: Boolean? = null, - val didSubmitEnhancedDocVJob: Boolean? = null, -) diff --git a/android/src/main/kotlin/com/smileidentity/flutter/results/SmartSelfieCaptureResult.kt b/android/src/main/kotlin/com/smileidentity/flutter/results/SmartSelfieCaptureResult.kt deleted file mode 100644 index 5f0a3c6..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/results/SmartSelfieCaptureResult.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.smileidentity.flutter.results -import com.smileidentity.models.v2.SmartSelfieResponse -import java.io.File - -data class SmartSelfieCaptureResult( - val selfieFile: File? = null, - val livenessFiles: List? = null, - val apiResponse: SmartSelfieResponse? = null, - val didSubmitBiometricKycJob: Boolean? = null, -) diff --git a/android/src/main/kotlin/com/smileidentity/flutter/utils/DocumentCaptureResultAdapter.kt b/android/src/main/kotlin/com/smileidentity/flutter/utils/DocumentCaptureResultAdapter.kt deleted file mode 100644 index 194244d..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/utils/DocumentCaptureResultAdapter.kt +++ /dev/null @@ -1,102 +0,0 @@ -package com.smileidentity.flutter.utils - -import com.smileidentity.flutter.results.DocumentCaptureResult -import com.squareup.moshi.FromJson -import com.squareup.moshi.JsonAdapter -import com.squareup.moshi.JsonReader -import com.squareup.moshi.JsonWriter -import com.squareup.moshi.Moshi -import com.squareup.moshi.ToJson -import java.io.File -import java.lang.reflect.Type - -class DocumentCaptureResultAdapter : JsonAdapter() { - @FromJson - override fun fromJson(reader: JsonReader): DocumentCaptureResult { - reader.beginObject() - var selfieFile: File? = null - var frontFile: File? = null - var backFile: File? = null - var livenessFiles: MutableList? = null - var didSubmitDocumentVerificationJob: Boolean? = null - var didSubmitEnhancedDocVJob: Boolean? = null - while (reader.hasNext()) { - when (reader.nextName()) { - "selfieFile" -> selfieFile = reader.nextString()?.let { File(it) } - "documentFrontFile" -> frontFile = reader.nextString()?.let { File(it) } - "documentBackFile" -> backFile = reader.nextString()?.let { File(it) } - "livenessFiles" -> { - livenessFiles = mutableListOf() - reader.beginArray() - while (reader.hasNext()) { - reader.nextString()?.let { livenessFiles.add(File(it)) } - } - reader.endArray() - } - - "didSubmitDocumentVerificationJob" -> - didSubmitDocumentVerificationJob = - reader.nextBoolean() - - "didSubmitEnhancedDocVJob" -> didSubmitEnhancedDocVJob = reader.nextBoolean() - else -> reader.skipValue() - } - } - reader.endObject() - - return DocumentCaptureResult( - selfieFile = selfieFile, - documentFrontFile = frontFile, - documentBackFile = backFile, - livenessFiles = livenessFiles, - didSubmitDocumentVerificationJob = didSubmitDocumentVerificationJob, - didSubmitEnhancedDocVJob = didSubmitEnhancedDocVJob, - ) - } - - @ToJson - override fun toJson(writer: JsonWriter, value: DocumentCaptureResult?) { - if (value == null) { - writer.nullValue() - return - } - - writer.beginObject() - writer.name("selfieFile").value(value.selfieFile?.absolutePath) - writer.name("documentFrontFile").value(value.documentFrontFile?.absolutePath) - writer.name("documentBackFile").value(value.documentBackFile?.absolutePath) - - writer.name("livenessFiles") - if (value.livenessFiles == null) { - writer.nullValue() - } else { - writer.beginArray() - for (file in value.livenessFiles) { - writer.value(file.absolutePath) - } - writer.endArray() - } - - writer - .name("didSubmitDocumentVerificationJob") - .value(value.didSubmitDocumentVerificationJob) - writer.name("didSubmitEnhancedDocVJob").value(value.didSubmitEnhancedDocVJob) - - writer.endObject() - } - - companion object { - val FACTORY = - object : Factory { - override fun create( - type: Type, - annotations: Set, - moshi: Moshi, - ): JsonAdapter<*>? = if (type == DocumentCaptureResult::class.java) { - DocumentCaptureResultAdapter() - } else { - null - } - } - } -} diff --git a/android/src/main/kotlin/com/smileidentity/flutter/utils/SelfieCaptureResultAdapter.kt b/android/src/main/kotlin/com/smileidentity/flutter/utils/SelfieCaptureResultAdapter.kt deleted file mode 100644 index 922539b..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/utils/SelfieCaptureResultAdapter.kt +++ /dev/null @@ -1,93 +0,0 @@ -package com.smileidentity.flutter.utils - -import com.smileidentity.SmileID -import com.smileidentity.flutter.results.SmartSelfieCaptureResult -import com.smileidentity.models.v2.SmartSelfieResponse -import com.squareup.moshi.FromJson -import com.squareup.moshi.JsonAdapter -import com.squareup.moshi.JsonAdapter.Factory -import com.squareup.moshi.JsonReader -import com.squareup.moshi.JsonWriter -import com.squareup.moshi.ToJson -import java.io.File - -class SelfieCaptureResultAdapter : JsonAdapter() { - @FromJson - override fun fromJson(reader: JsonReader): SmartSelfieCaptureResult { - reader.beginObject() - var selfieFile: File? = null - var livenessFiles: List? = null - var didSubmitBiometricKycJob: Boolean? = false - var apiResponse: SmartSelfieResponse? = null - - while (reader.hasNext()) { - when (reader.nextName()) { - "selfieFile" -> selfieFile = reader.nextString()?.let { File(it) } - "livenessFiles" -> { - // Assuming livenessFiles is an array of file paths in the JSON - val files = mutableListOf() - reader.beginArray() - while (reader.hasNext()) { - reader.nextString()?.let { files.add(File(it)) } - } - reader.endArray() - livenessFiles = files - } - - "apiResponse" -> - apiResponse = - SmileID.moshi.adapter(SmartSelfieResponse::class.java).fromJson(reader) - "didSubmitBiometricKycJob" -> reader.nextBoolean() - - else -> reader.skipValue() - } - } - - reader.endObject() - return SmartSelfieCaptureResult( - selfieFile = selfieFile, - livenessFiles = livenessFiles, - apiResponse = apiResponse, - didSubmitBiometricKycJob = didSubmitBiometricKycJob, - ) - } - - @ToJson - override fun toJson(writer: JsonWriter, value: SmartSelfieCaptureResult?) { - if (value == null) { - writer.nullValue() - return - } - writer.beginObject() - writer.name("selfieFile").value(value.selfieFile?.absolutePath) - - writer.name("livenessFiles") - writer.beginArray() - value.livenessFiles?.forEach { writer.value(it.absolutePath) } - writer.endArray() - writer.name("didSubmitBiometricKycJob").value(value.didSubmitBiometricKycJob) - writer.name("apiResponse") - if (value.apiResponse != null) { - SmileID.moshi.adapter(SmartSelfieResponse::class.java).toJson( - writer, - value.apiResponse, - ) - } else { - writer.nullValue() - } - writer.endObject() - } - - companion object { - val FACTORY = - Factory { type, annotations, moshi -> - if (type == - SmartSelfieCaptureResult::class.java - ) { - SelfieCaptureResultAdapter() - } else { - null - } - } - } -} diff --git a/android/src/main/kotlin/com/smileidentity/flutter/utils/SmileIDUtils.kt b/android/src/main/kotlin/com/smileidentity/flutter/utils/SmileIDUtils.kt deleted file mode 100644 index bfd9177..0000000 --- a/android/src/main/kotlin/com/smileidentity/flutter/utils/SmileIDUtils.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.smileidentity.flutter.utils -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale -import java.util.TimeZone - -/** - * Converts current time to ISO8601 string with milliseconds in UTC - * Format: yyyy-MM-dd'T'HH:mm:ss.SSS'Z' - */ -internal fun getCurrentIsoTimestamp(): String { - val pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" - val sdf = SimpleDateFormat(pattern, Locale.US) - sdf.timeZone = TimeZone.getTimeZone("UTC") - return sdf.format(Date()) -} diff --git a/android/src/test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt b/android/src/test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt deleted file mode 100644 index ce5035a..0000000 --- a/android/src/test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt +++ /dev/null @@ -1,77 +0,0 @@ -package com.smileidentity.flutter - -import FlutterAuthenticationRequest -import FlutterAuthenticationResponse -import FlutterEnhancedKycAsyncResponse -import FlutterEnhancedKycRequest -import SmileIDApi -import io.mockk.coEvery -import io.mockk.coVerify -import io.mockk.confirmVerified -import io.mockk.mockk -import kotlin.test.Test - -/* - * This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation. - * - * Once you have built the plugin's example app, you can run these tests from the command - * line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or - * you can run them directly from IDEs that support JUnit such as Android Studio. - */ -internal class SmileIDPluginTest { - @Test - fun `when we call authenticate and pass a request object, we get a successful callback`() { - val request = mockk() - val callback = mockk<(Result) -> Unit>() - val api = mockk() - - coEvery { - api.authenticate( - request = request, - callback = callback, - ) - } returns Unit - - api.authenticate( - request = request, - callback = callback, - ) - - coVerify { - api.authenticate( - request = request, - callback = callback, - ) - } - - confirmVerified(api) - } - - @Test - fun `when we call doEnhancedKycAsync with a request object, we get a successful callback`() { - val request = mockk() - val callback = mockk<(Result) -> Unit>() - val api = mockk() - - coEvery { - api.doEnhancedKycAsync( - request = request, - callback = callback, - ) - } returns Unit - - api.doEnhancedKycAsync( - request = request, - callback = callback, - ) - - coVerify { - api.doEnhancedKycAsync( - request = request, - callback = callback, - ) - } - - confirmVerified(api) - } -} diff --git a/example/android/app/build.gradle.kts b/example/android/app/build.gradle.kts index 65908ba..ef880e9 100644 --- a/example/android/app/build.gradle.kts +++ b/example/android/app/build.gradle.kts @@ -1,8 +1,7 @@ plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) - alias(libs.plugins.ktlint) - alias(libs.plugins.ktlint) + alias(libs.plugins.flutter.gradle.plugin) } android { @@ -16,7 +15,7 @@ android { defaultConfig { applicationId = "com.smileidentity.flutter.sample" minSdk = 21 - targetSdk = flutter.targetSdkVersion + targetSdk = 35 versionCode = 1 versionName = "1.0.0" } @@ -32,4 +31,18 @@ android { jvmTarget = "17" freeCompilerArgs += listOf("-Xskip-metadata-version-check") } + + val checkSmileConfigFileTaskName = "checkSmileConfigFile" + tasks.register(checkSmileConfigFileTaskName) { + doLast { + val configFile = file("src/main/assets/smile_config.json") + if (configFile.readText().isBlank()) { + throw IllegalArgumentException("Empty smile_config.json file in src/main/assets!") + } + } + } + + tasks.named("assemble") { + dependsOn(checkSmileConfigFileTaskName) + } } diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 4c3d852..eaf7c9d 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,7 +1,6 @@ ("clean") { delete(rootProject.layout.buildDirectory) } - -// this diff --git a/example/android/settings.gradle.kts b/example/android/settings.gradle.kts index 9e69202..4edc714 100644 --- a/example/android/settings.gradle.kts +++ b/example/android/settings.gradle.kts @@ -3,7 +3,7 @@ pluginManagement { val properties = java.util.Properties() file("local.properties").inputStream().use { properties.load(it) } val flutterSdkPath = properties.getProperty("flutter.sdk") - requireNotNull(flutterSdkPath) { "flutter.sdk not set in local.properties" } + checkNotNull(flutterSdkPath) { "flutter.sdk not set in local.properties" } flutterSdkPath } @@ -17,15 +17,16 @@ pluginManagement { } dependencyResolutionManagement { + repositories { + google() + mavenCentral() + } + versionCatalogs { create("libs") { from(files("../../android/gradle/libs.versions.toml")) } } - repositories { - google() - mavenCentral() - gradlePluginPortal() - } } + include(":app") From 8246256d2d53137343043a7c20bda63ef653cdc9 Mon Sep 17 00:00:00 2001 From: Harun Wangereka Date: Mon, 9 Jun 2025 14:48:05 +0300 Subject: [PATCH 06/18] Created a lib folder and moved android lib logic to the folder --- android/lib/src/build.gradle.kts | 72 + android/lib/src/main/AndroidManifest.xml | 1 + .../com/smileidentity/flutter/Mapper.kt | 601 ++++ .../flutter/SmileComposablePlatformView.kt | 112 + .../flutter/SmileIDBiometricKYC.kt | 111 + .../flutter/SmileIDDocumentCaptureView.kt | 153 + .../flutter/SmileIDDocumentVerification.kt | 96 + .../SmileIDEnhancedDocumentVerification.kt | 105 + .../smileidentity/flutter/SmileIDPlugin.kt | 470 +++ .../SmileIDSmartSelfieAuthentication.kt | 51 + .../flutter/SmileIDSmartSelfieCaptureView.kt | 197 ++ .../flutter/SmileIDSmartSelfieEnrollment.kt | 51 + .../SmileSelfieComposablePlatformView.kt | 49 + ...mileIDSmartSelfieAuthenticationEnhanced.kt | 51 + .../SmileIDSmartSelfieEnrollmentEnhanced.kt | 51 + .../flutter/generated/SmileIDMessages.g.kt | 2864 +++++++++++++++++ .../flutter/results/DocumentCaptureResult.kt | 12 + .../results/SmartSelfieCaptureResult.kt | 10 + .../utils/DocumentCaptureResultAdapter.kt | 102 + .../utils/SelfieCaptureResultAdapter.kt | 93 + .../flutter/utils/SmileIDUtils.kt | 16 + .../flutter/SmileIDPluginTest.kt | 77 + 22 files changed, 5345 insertions(+) create mode 100644 android/lib/src/build.gradle.kts create mode 100644 android/lib/src/main/AndroidManifest.xml create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/Mapper.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/SmileComposablePlatformView.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDBiometricKYC.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentCaptureView.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentVerification.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDEnhancedDocumentVerification.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieAuthentication.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieCaptureView.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieEnrollment.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/SmileSelfieComposablePlatformView.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieAuthenticationEnhanced.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieEnrollmentEnhanced.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/generated/SmileIDMessages.g.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/results/DocumentCaptureResult.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/results/SmartSelfieCaptureResult.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/utils/DocumentCaptureResultAdapter.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/utils/SelfieCaptureResultAdapter.kt create mode 100644 android/lib/src/main/kotlin/com/smileidentity/flutter/utils/SmileIDUtils.kt create mode 100644 android/lib/src/test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt diff --git a/android/lib/src/build.gradle.kts b/android/lib/src/build.gradle.kts new file mode 100644 index 0000000..40744b4 --- /dev/null +++ b/android/lib/src/build.gradle.kts @@ -0,0 +1,72 @@ +plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.ktlint) + alias(libs.plugins.compose.compiler) +} + +android { + namespace = "com.smileidentity.flutter" + compileSdk = 35 + + defaultConfig { + minSdk = 21 + + // Read version from pubspec.yaml for setWrapperInfo + val pubspecYaml = File("../pubspec.yaml") + val pubspecText = pubspecYaml.readText() + val versionRegex = Regex("""version:\s*(.+)""") + val versionMatch = versionRegex.find(pubspecText) + val version = if (versionMatch != null) { + pubspecText.split(Regex("""version:\s*"""))[1].split("\n")[0].trim() + } else { + "11.0.0" + } + buildConfigField("String", "SMILE_ID_VERSION", "\"$version\"") + } + + buildFeatures { + buildConfig = true + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = "17" + freeCompilerArgs += listOf("-Xskip-metadata-version-check") // metadata version check skip flag + } + + sourceSets { + getByName("main").java.srcDirs("src/main/kotlin") + getByName("test").java.srcDirs("src/test/kotlin") + } + + lint { + disable.add("NullSafeMutableLiveData") + } + + buildFeatures.compose = true + if (!kotlinVersion.startsWith("2")) { + composeOptions { + kotlinCompilerExtensionVersion = kotlinCompilerExtension + } + } +} + +dependencies { + implementation(libs.smile.id) + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.compose.viewmodel) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.fragment) + implementation(libs.kotlin.coroutines) + implementation(libs.kotlin.immutable.collections) + implementation(libs.mlkit) + + testImplementation(libs.kotlin.test) + testImplementation(libs.mockk) +} diff --git a/android/lib/src/main/AndroidManifest.xml b/android/lib/src/main/AndroidManifest.xml new file mode 100644 index 0000000..cc947c5 --- /dev/null +++ b/android/lib/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/Mapper.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/Mapper.kt new file mode 100644 index 0000000..35e897f --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/Mapper.kt @@ -0,0 +1,601 @@ +package com.smileidentity.flutter + +import FlutterActionResult +import FlutterActions +import FlutterAntifraud +import FlutterAuthenticationRequest +import FlutterAuthenticationResponse +import FlutterAvailableIdType +import FlutterBankCode +import FlutterBiometricKycJobResult +import FlutterBiometricKycJobStatusResponse +import FlutterConfig +import FlutterConsentInfo +import FlutterConsentInformation +import FlutterCountry +import FlutterCountryInfo +import FlutterDocumentVerificationJobResult +import FlutterDocumentVerificationJobStatusResponse +import FlutterEnhancedDocumentVerificationJobResult +import FlutterEnhancedDocumentVerificationJobStatusResponse +import FlutterEnhancedKycAsyncResponse +import FlutterEnhancedKycRequest +import FlutterEnhancedKycResponse +import FlutterHostedWeb +import FlutterIdInfo +import FlutterIdSelection +import FlutterIdType +import FlutterImageLinks +import FlutterImageType +import FlutterJobStatusRequest +import FlutterJobType +import FlutterJobTypeV2 +import FlutterPartnerParams +import FlutterPrepUploadRequest +import FlutterPrepUploadResponse +import FlutterProductsConfigRequest +import FlutterProductsConfigResponse +import FlutterServicesResponse +import FlutterSmartSelfieJobResult +import FlutterSmartSelfieJobStatusResponse +import FlutterSmartSelfieResponse +import FlutterSmartSelfieStatus +import FlutterSuspectUser +import FlutterUploadImageInfo +import FlutterUploadRequest +import FlutterValidDocument +import FlutterValidDocumentsResponse +import com.smileidentity.flutter.utils.getCurrentIsoTimestamp +import com.smileidentity.models.ActionResult +import com.smileidentity.models.Actions +import com.smileidentity.models.Antifraud +import com.smileidentity.models.AuthenticationRequest +import com.smileidentity.models.AuthenticationResponse +import com.smileidentity.models.AvailableIdType +import com.smileidentity.models.BankCode +import com.smileidentity.models.BiometricKycJobResult +import com.smileidentity.models.BiometricKycJobStatusResponse +import com.smileidentity.models.Config +import com.smileidentity.models.ConsentInfo +import com.smileidentity.models.ConsentInformation +import com.smileidentity.models.ConsentedInformation +import com.smileidentity.models.Country +import com.smileidentity.models.CountryInfo +import com.smileidentity.models.DocumentVerificationJobResult +import com.smileidentity.models.DocumentVerificationJobStatusResponse +import com.smileidentity.models.EnhancedDocumentVerificationJobResult +import com.smileidentity.models.EnhancedDocumentVerificationJobStatusResponse +import com.smileidentity.models.EnhancedKycAsyncResponse +import com.smileidentity.models.EnhancedKycRequest +import com.smileidentity.models.EnhancedKycResponse +import com.smileidentity.models.HostedWeb +import com.smileidentity.models.IdInfo +import com.smileidentity.models.IdSelection +import com.smileidentity.models.IdType +import com.smileidentity.models.ImageLinks +import com.smileidentity.models.ImageType +import com.smileidentity.models.JobResult +import com.smileidentity.models.JobStatusRequest +import com.smileidentity.models.JobType +import com.smileidentity.models.PartnerParams +import com.smileidentity.models.PrepUploadRequest +import com.smileidentity.models.PrepUploadResponse +import com.smileidentity.models.ProductsConfigRequest +import com.smileidentity.models.ProductsConfigResponse +import com.smileidentity.models.ServicesResponse +import com.smileidentity.models.SmartSelfieJobResult +import com.smileidentity.models.SmartSelfieJobStatusResponse +import com.smileidentity.models.SuspectUser +import com.smileidentity.models.UploadImageInfo +import com.smileidentity.models.UploadRequest +import com.smileidentity.models.ValidDocument +import com.smileidentity.models.ValidDocumentsResponse +import com.smileidentity.models.v2.JobType as JobTypeV2 +import com.smileidentity.models.v2.SmartSelfieResponse +import com.smileidentity.models.v2.SmartSelfieStatus +import java.io.File + +/** + * Pigeon does not allow non nullable types in this example here + * + * final Map extras; + * + * Error: pigeons/messages.dart:18: Generic type arguments must be nullable in field "extras" in + * class "FlutterPartnerParams". + * + * The fix is these two helper functions to convert maps to nullable types, and vice versa + */ +fun convertNullableMapToNonNull(map: Map?): Map = map + ?.filterKeys { it != null } + ?.filterValues { it != null } + ?.mapKeys { it.key!! } + ?.mapValues { it.value!! } ?: mapOf() + +fun convertNonNullMapToNullable(map: Map): Map = map + .mapKeys { it.key } + .mapValues { it.value } + +fun FlutterJobType.toRequest() = when (this) { + FlutterJobType.ENHANCEDKYC -> JobType.EnhancedKyc + FlutterJobType.DOCUMENTVERIFICATION -> JobType.DocumentVerification + FlutterJobType.BIOMETRICKYC -> JobType.BiometricKyc + FlutterJobType.ENHANCEDDOCUMENTVERIFICATION -> JobType.EnhancedDocumentVerification + FlutterJobType.SMARTSELFIEENROLLMENT -> JobType.SmartSelfieEnrollment + FlutterJobType.SMARTSELFIEAUTHENTICATION -> JobType.SmartSelfieAuthentication +} + +fun JobType.toResponse() = when (this) { + JobType.EnhancedKyc -> FlutterJobType.ENHANCEDKYC + JobType.DocumentVerification -> FlutterJobType.DOCUMENTVERIFICATION + JobType.BiometricKyc -> FlutterJobType.BIOMETRICKYC + JobType.EnhancedDocumentVerification -> FlutterJobType.ENHANCEDDOCUMENTVERIFICATION + JobType.SmartSelfieEnrollment -> FlutterJobType.SMARTSELFIEENROLLMENT + JobType.SmartSelfieAuthentication -> FlutterJobType.SMARTSELFIEAUTHENTICATION + else -> TODO("Not yet implemented") +} + +fun FlutterJobTypeV2.toRequest() = when (this) { + FlutterJobTypeV2.SMARTSELFIEAUTHENTICATION -> JobTypeV2.SmartSelfieAuthentication + FlutterJobTypeV2.SMARTSELFIEENROLLMENT -> JobTypeV2.SmartSelfieEnrollment +} + +fun JobTypeV2.toResponse() = when (this) { + JobTypeV2.SmartSelfieAuthentication -> FlutterJobTypeV2.SMARTSELFIEAUTHENTICATION + JobTypeV2.SmartSelfieEnrollment -> FlutterJobTypeV2.SMARTSELFIEENROLLMENT + else -> TODO("Not yet implemented") +} + +fun FlutterAuthenticationRequest.toRequest() = AuthenticationRequest( + jobType = jobType.toRequest(), + country = country, + idType = idType, + updateEnrolledImage = updateEnrolledImage, + jobId = jobId, + userId = userId, +) + +fun PartnerParams.toResponse() = FlutterPartnerParams( + jobType = jobType?.toResponse(), + jobId = jobId, + userId = userId, + extras = convertNonNullMapToNullable(extras), +) + +fun FlutterPartnerParams.toRequest() = PartnerParams( + jobType = jobType?.toRequest(), + jobId = jobId, + userId = userId, + extras = convertNullableMapToNonNull(extras), +) + +fun ConsentInfo.toRequest() = FlutterConsentInfo( + canAccess = canAccess, + consentRequired = consentRequired, +) + +fun AuthenticationResponse.toResponse() = FlutterAuthenticationResponse( + success = success, + signature = signature, + timestamp = timestamp, + partnerParams = partnerParams.toResponse(), + callbackUrl = callbackUrl, + consentInfo = consentInfo?.toRequest(), +) + +fun FlutterPrepUploadRequest.toRequest() = PrepUploadRequest( + partnerParams = partnerParams.toRequest(), + callbackUrl = callbackUrl, + allowNewEnroll = allowNewEnroll, + partnerId = partnerId, + sourceSdk = "android (flutter)", + timestamp = timestamp, + signature = signature, +) + +fun PrepUploadResponse.toResponse() = FlutterPrepUploadResponse( + code = code, + refId = refId, + uploadUrl = uploadUrl, + smileJobId = smileJobId, +) + +fun FlutterUploadRequest.toRequest() = UploadRequest( + images = images.mapNotNull { it?.toRequest() }, + idInfo = idInfo?.toRequest(), +) + +fun FlutterUploadImageInfo.toRequest() = UploadImageInfo( + imageTypeId = imageTypeId.toRequest(), + image = File(imageName), +) + +fun FlutterImageType.toRequest() = when (this) { + FlutterImageType.SELFIEJPGFILE -> ImageType.SelfieJpgFile + FlutterImageType.IDCARDJPGFILE -> ImageType.IdCardJpgFile + FlutterImageType.SELFIEJPGBASE64 -> ImageType.SelfieJpgBase64 + FlutterImageType.IDCARDJPGBASE64 -> ImageType.IdCardJpgBase64 + FlutterImageType.LIVENESSJPGFILE -> ImageType.LivenessJpgFile + FlutterImageType.IDCARDREARJPGFILE -> ImageType.IdCardRearJpgFile + FlutterImageType.LIVENESSJPGBASE64 -> ImageType.LivenessJpgBase64 + FlutterImageType.IDCARDREARJPGBASE64 -> ImageType.IdCardRearJpgBase64 +} + +fun FlutterIdInfo.toRequest() = IdInfo( + country = country, + idType = idType, + idNumber = idNumber, + firstName = firstName, + middleName = middleName, + lastName = lastName, + dob = dob, + bankCode = bankCode, + entered = entered, +) + +fun FlutterConsentInformation.toRequest() = ConsentInformation( + consented = ConsentedInformation( + consentGrantedDate = consentGrantedDate, + personalDetails = personalDetailsConsentGranted, + contactInformation = contactInfoConsentGranted, + documentInformation = documentInfoConsentGranted, + ), +) + +fun FlutterEnhancedKycRequest.toRequest() = EnhancedKycRequest( + country = country, + idType = idType, + idNumber = idNumber, + firstName = firstName, + middleName = middleName, + lastName = lastName, + dob = dob, + phoneNumber = phoneNumber, + bankCode = bankCode, + callbackUrl = callbackUrl, + partnerParams = partnerParams.toRequest(), + sourceSdk = "android (flutter)", + timestamp = timestamp, + signature = signature, + consentInformation = + consentInformation?.toRequest() ?: ConsentInformation( + consented = ConsentedInformation( + consentGrantedDate = getCurrentIsoTimestamp(), + personalDetails = false, + contactInformation = false, + documentInformation = false, + ), + ), +) + +fun EnhancedKycResponse.toResponse() = FlutterEnhancedKycResponse( + smileJobId = smileJobId, + partnerParams = partnerParams.toResponse(), + resultText = resultText, + resultCode = resultCode, + actions = actions.toResponse(), + country = country, + idType = idType, + idNumber = idNumber, + fullName = fullName, + expirationDate = expirationDate, + dob = dob, + base64Photo = base64Photo, +) + +fun EnhancedKycAsyncResponse.toResponse() = FlutterEnhancedKycAsyncResponse( + success = success, +) + +fun Actions.toResponse() = FlutterActions( + documentCheck = documentCheck.toResponse(), + humanReviewCompare = humanReviewCompare.toResponse(), + humanReviewDocumentCheck = humanReviewDocumentCheck.toResponse(), + humanReviewLivenessCheck = humanReviewLivenessCheck.toResponse(), + humanReviewSelfieCheck = humanReviewSelfieCheck.toResponse(), + humanReviewUpdateSelfie = humanReviewUpdateSelfie.toResponse(), + livenessCheck = livenessCheck.toResponse(), + registerSelfie = registerSelfie.toResponse(), + returnPersonalInfo = returnPersonalInfo.toResponse(), + selfieCheck = selfieCheck.toResponse(), + selfieProvided = selfieProvided.toResponse(), + selfieToIdAuthorityCompare = selfieToIdAuthorityCompare.toResponse(), + selfieToIdCardCompare = selfieToIdCardCompare.toResponse(), + selfieToRegisteredSelfieCompare = selfieToRegisteredSelfieCompare.toResponse(), + updateRegisteredSelfieOnFile = updateRegisteredSelfieOnFile.toResponse(), + verifyDocument = verifyDocument.toResponse(), + verifyIdNumber = verifyIdNumber.toResponse(), +) + +fun ActionResult.toResponse() = when (this) { + ActionResult.Passed -> FlutterActionResult.PASSED + ActionResult.Completed -> FlutterActionResult.COMPLETED + ActionResult.Approved -> FlutterActionResult.APPROVED + ActionResult.Verified -> FlutterActionResult.VERIFIED + ActionResult.ProvisionallyApproved -> FlutterActionResult.PROVISIONALLYAPPROVED + ActionResult.Returned -> FlutterActionResult.RETURNED + ActionResult.NotReturned -> FlutterActionResult.NOTRETURNED + ActionResult.Failed -> FlutterActionResult.FAILED + ActionResult.Rejected -> FlutterActionResult.REJECTED + ActionResult.UnderReview -> FlutterActionResult.UNDERREVIEW + ActionResult.UnableToDetermine -> FlutterActionResult.UNABLETODETERMINE + ActionResult.NotApplicable -> FlutterActionResult.NOTAPPLICABLE + ActionResult.NotVerified -> FlutterActionResult.NOTVERIFIED + ActionResult.NotDone -> FlutterActionResult.NOTDONE + ActionResult.IssuerUnavailable -> FlutterActionResult.ISSUERUNAVAILABLE + ActionResult.IdAuthorityPhotoNotAvailable -> + FlutterActionResult.IDAUTHORITYPHOTONOTAVAILABLE + + ActionResult.SentToHumanReview -> FlutterActionResult.SENTTOHUMANREVIEW + ActionResult.Unknown -> FlutterActionResult.UNKNOWN +} + +fun ImageLinks.toResponse() = FlutterImageLinks( + selfieImageUrl = selfieImageUrl, + error = error, +) + +fun Antifraud.toResponse() = FlutterAntifraud( + suspectUsers = suspectUsers.map { it.toResponse() }, +) + +fun SuspectUser.toResponse() = FlutterSuspectUser( + reason = reason, + userId = userId, +) + +fun FlutterJobStatusRequest.toRequest() = JobStatusRequest( + userId = userId, + jobId = jobId, + includeImageLinks = includeImageLinks, + includeHistory = includeHistory, + partnerId = partnerId, + timestamp = timestamp, + signature = signature, +) + +fun SmartSelfieJobStatusResponse.toResponse() = FlutterSmartSelfieJobStatusResponse( + timestamp = timestamp, + jobComplete = jobComplete, + jobSuccess = jobSuccess, + code = code, + result = result?.toResponse() as? FlutterSmartSelfieJobResult, + resultString = result?.toResponse() as? String, + imageLinks = imageLinks?.toResponse(), +) + +fun SmartSelfieJobResult.toResponse(): Any = when (this) { + is JobResult.Freeform -> this.result + is SmartSelfieJobResult.Entry -> + FlutterSmartSelfieJobResult( + actions = actions.toResponse(), + resultCode = resultCode, + resultText = resultText, + smileJobId = smileJobId, + partnerParams = partnerParams.toResponse(), + confidence = confidence, + ) +} + +fun SmartSelfieStatus.toResponse() = when (this) { + SmartSelfieStatus.Approved -> FlutterSmartSelfieStatus.APPROVED + SmartSelfieStatus.Pending -> FlutterSmartSelfieStatus.PENDING + SmartSelfieStatus.Rejected -> FlutterSmartSelfieStatus.REJECTED + SmartSelfieStatus.Unknown -> FlutterSmartSelfieStatus.UNKNOWN +} + +fun SmartSelfieResponse.toResponse() = FlutterSmartSelfieResponse( + code = code, + createdAt = createdAt, + jobId = jobId, + jobType = jobType.toResponse(), + message = message, + partnerId = partnerId, + partnerParams = convertNonNullMapToNullable(partnerParams), + status = status.toResponse(), + updatedAt = updatedAt, + userId = userId, +) + +fun DocumentVerificationJobStatusResponse.toResponse() = + FlutterDocumentVerificationJobStatusResponse( + timestamp = timestamp, + jobComplete = jobComplete, + jobSuccess = jobSuccess, + code = code, + result = result?.toResponse() as? FlutterDocumentVerificationJobResult, + resultString = result?.toResponse() as? String, + imageLinks = imageLinks?.toResponse(), + ) + +fun DocumentVerificationJobResult.toResponse(): Any = when (this) { + is JobResult.Freeform -> this.result + is DocumentVerificationJobResult.Entry -> + FlutterDocumentVerificationJobResult( + actions = actions.toResponse(), + resultCode = resultCode, + resultText = resultText, + smileJobId = smileJobId, + partnerParams = partnerParams.toResponse(), + country = country, + idType = idType, + fullName = fullName, + idNumber = idNumber, + dob = dob, + gender = gender, + expirationDate = expirationDate, + documentImageBase64 = documentImageBase64, + phoneNumber = phoneNumber, + phoneNumber2 = phoneNumber2, + address = address, + ) +} + +fun BiometricKycJobStatusResponse.toResponse() = FlutterBiometricKycJobStatusResponse( + timestamp = timestamp, + jobComplete = jobComplete, + jobSuccess = jobSuccess, + code = code, + result = result?.toResponse() as? FlutterBiometricKycJobResult, + resultString = result?.toResponse() as? String, + imageLinks = imageLinks?.toResponse(), +) + +fun BiometricKycJobResult.toResponse(): Any = when (this) { + is JobResult.Freeform -> this.result + is BiometricKycJobResult.Entry -> + FlutterBiometricKycJobResult( + actions = actions.toResponse(), + resultCode = resultCode, + resultText = resultText, + resultType = resultType, + smileJobId = smileJobId, + partnerParams = partnerParams.toResponse(), + antifraud = antifraud?.toResponse(), + dob = dob, + photoBase64 = photoBase64, + gender = gender, + idType = idType, + address = address, + country = country, + documentImageBase64 = documentImageBase64, + fullData = fullData?.mapKeys { it.key }?.mapValues { it.value.toString() }, + fullName = fullName, + idNumber = idNumber, + phoneNumber = phoneNumber, + phoneNumber2 = phoneNumber2, + expirationDate = expirationDate, + ) +} + +fun EnhancedDocumentVerificationJobStatusResponse.toResponse() = + FlutterEnhancedDocumentVerificationJobStatusResponse( + timestamp = timestamp, + jobComplete = jobComplete, + jobSuccess = jobSuccess, + code = code, + result = result?.toResponse() as? FlutterEnhancedDocumentVerificationJobResult, + resultString = result?.toResponse() as? String, + imageLinks = imageLinks?.toResponse(), + ) + +fun EnhancedDocumentVerificationJobResult.toResponse(): Any = when (this) { + is JobResult.Freeform -> this.result + is EnhancedDocumentVerificationJobResult.Entry -> + FlutterEnhancedDocumentVerificationJobResult( + actions = actions.toResponse(), + resultCode = resultCode, + resultText = resultText, + smileJobId = smileJobId, + resultType = resultType, + partnerParams = partnerParams.toResponse(), + antifraud = antifraud?.toResponse(), + dob = dob, + photoBase64 = photoBase64, + gender = gender, + idType = idType, + address = address, + country = country, + documentImageBase64 = documentImageBase64, + fullData = fullData?.mapKeys { it.key }?.mapValues { it.value.toString() }, + fullName = fullName, + idNumber = idNumber, + phoneNumber = phoneNumber, + phoneNumber2 = phoneNumber2, + expirationDate = expirationDate, + ) +} + +fun FlutterProductsConfigRequest.toRequest() = ProductsConfigRequest( + partnerId = partnerId, + timestamp = timestamp, + signature = signature, +) + +fun ProductsConfigResponse.toResponse() = FlutterProductsConfigResponse( + consentRequired = consentRequired.mapKeys { it.key }, + idSelection = idSelection.toResponse(), +) + +fun IdSelection.toResponse() = FlutterIdSelection( + basicKyc = basicKyc.mapKeys { it.key }, + biometricKyc = biometricKyc.mapKeys { it.key }, + enhancedKyc = enhancedKyc.mapKeys { it.key }, + documentVerification = documentVerification.mapKeys { it.key }, +) + +fun ValidDocumentsResponse.toResponse() = FlutterValidDocumentsResponse( + validDocuments = validDocuments.map { it.toResponse() }, +) + +fun ValidDocument.toResponse() = FlutterValidDocument( + country = country.toResponse(), + idTypes = idTypes.map { it.toResponse() }, +) + +fun Country.toResponse() = FlutterCountry( + name = name, + code = code, + continent = continent, +) + +fun IdType.toResponse() = FlutterIdType( + name = name, + code = code, + example = example.map { it }, + hasBack = hasBack, +) + +fun ServicesResponse.toResponse() = FlutterServicesResponse( + bankCodes = bankCodes.map { it.toResponse() }, + hostedWeb = hostedWeb.toResponse(), +) + +fun BankCode.toResponse() = FlutterBankCode( + name = name, + code = code, +) + +fun HostedWeb.toResponse() = FlutterHostedWeb( + basicKyc = basicKyc.groupBy { it.countryCode }.mapValues { it.value.first().toResponse() }, + biometricKyc = + biometricKyc + .groupBy { it.countryCode } + .mapValues { it.value.first().toResponse() }, + enhancedKyc = + enhancedKyc + .groupBy { it.countryCode } + .mapValues { it.value.first().toResponse() }, + documentVerification = + docVerification + .groupBy { it.countryCode } + .mapValues { it.value.first().toResponse() }, + enhancedKycSmartSelfie = + enhancedKycSmartSelfie + .groupBy { it.countryCode } + .mapValues { it.value.first().toResponse() }, + enhancedDocumentVerification = + enhancedDocumentVerification + .groupBy { it.countryCode } + .mapValues { it.value.first().toResponse() }, +) + +fun CountryInfo.toResponse() = FlutterCountryInfo( + countryCode = countryCode, + name = name, + availableIdTypes = availableIdTypes.map { it.toResponse() }, +) + +fun AvailableIdType.toResponse() = FlutterAvailableIdType( + idTypeKey = idTypeKey, + label = label, + requiredFields = requiredFields.map { it.name }, + testData = testData, + idNumberRegex = idNumberRegex, +) + +fun FlutterConfig.toRequest() = Config( + partnerId = partnerId, + authToken = authToken, + prodLambdaUrl = prodBaseUrl, + testLambdaUrl = sandboxBaseUrl, +) diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileComposablePlatformView.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileComposablePlatformView.kt new file mode 100644 index 0000000..507648a --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileComposablePlatformView.kt @@ -0,0 +1,112 @@ +package com.smileidentity.flutter + +import android.content.Context +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.platform.ComposeView +import androidx.lifecycle.ViewModelStore +import androidx.lifecycle.ViewModelStoreOwner +import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner +import com.smileidentity.SmileID +import io.flutter.Log +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.MethodChannel +import io.flutter.plugin.platform.PlatformView + +/** + * Base class for hosting Smile ID Composables in Flutter. This class handles flutter<>android + * result delivery, view initialization (incl. view model store), and boilerplate. Subclasses should + * implement [Content] to provide the actual Composable content. + */ +internal abstract class SmileComposablePlatformView( + context: Context, + viewTypeId: String, + viewId: Int, + messenger: BinaryMessenger, + args: Map, +) : PlatformView { + private val methodChannel = MethodChannel(messenger, "${viewTypeId}_$viewId") + + /** + * Creates a viewModelStore that is scoped to the FlutterView's lifecycle. Otherwise, state gets + * shared between multiple FlutterView instances since the default viewModelStore is at the + * Activity level and since we don't have a full Compose app or nav graph, the same viewModel + * ends up getting re-used + */ + private val viewModelStoreOwner = + object : ViewModelStoreOwner { + override val viewModelStore = ViewModelStore() + } + + private var view: ComposeView? = + ComposeView(context).apply { + setContent { + CompositionLocalProvider(LocalViewModelStoreOwner provides viewModelStoreOwner) { + Content(args) + } + } + } + + /** + * Implement this method to provide the actual Composable content for the view + * + * @param args The arguments passed from Flutter. It is the responsibility of the subclass to + * ensure the correct types are provided by the Flutter view and that they are parsed correctly + */ + @Composable + abstract fun Content(args: Map) + + /** + * Delivers a successful result back to Flutter as JSON. It is the flutter code's responsibility + * to parse this JSON string into the appropriate object + * + * @param result The success result object. NB! This object *must* be serializable by the + * [SmileID.moshi] instance! + */ + inline fun onSuccess(result: T) { + // At this point, we have a successful result from the native SDK. But, there is still a + // possibility of the JSON serializing erroring for whatever reason -- if such a thing + // happens, we still want to tell the caller that the overall operation was successful. + // However, we just may not be able to provide the result JSON. + val json = + try { + SmileID.moshi + .adapter(T::class.java) + .toJson(result) + } catch (e: Exception) { + Log.e("SmileComposablePlatformView", "Error serializing result", e) + Log.v("SmileComposablePlatformView", "Result is: $result") + "null" + } + methodChannel.invokeMethod("onSuccess", json) + } + + /** + * Delivers a successful result back to Flutter as JSON. It is the flutter code's responsibility + * to parse this JSON string into the appropriate object + * + * @param result The success result string + */ + fun onSuccessJson(result: String) { + methodChannel.invokeMethod("onSuccess", result) + } + + /** + * Delivers an error result back to Flutter + * + * @param throwable The throwable that caused the error. This will be converted to a string + * message and delivered back to Flutter, because a [Throwable] cannot be passed back to Flutter + */ + fun onError(throwable: Throwable) { + // Print the stack trace, since we can't provide the actual Throwable back to Flutter + throwable.printStackTrace() + methodChannel.invokeMethod("onError", throwable.message) + } + + override fun getView() = view + + override fun dispose() { + // Clear references to the view to avoid memory leaks + view = null + } +} diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDBiometricKYC.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDBiometricKYC.kt new file mode 100644 index 0000000..edce741 --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDBiometricKYC.kt @@ -0,0 +1,111 @@ +package com.smileidentity.flutter + +import android.content.Context +import androidx.compose.runtime.Composable +import com.smileidentity.SmileID +import com.smileidentity.compose.BiometricKYC +import com.smileidentity.flutter.results.SmartSelfieCaptureResult +import com.smileidentity.flutter.utils.SelfieCaptureResultAdapter +import com.smileidentity.flutter.utils.getCurrentIsoTimestamp +import com.smileidentity.models.ConsentInformation +import com.smileidentity.models.ConsentedInformation +import com.smileidentity.models.IdInfo +import com.smileidentity.results.SmileIDResult +import com.smileidentity.util.randomJobId +import com.smileidentity.util.randomUserId +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.StandardMessageCodec +import io.flutter.plugin.platform.PlatformView +import io.flutter.plugin.platform.PlatformViewFactory +import kotlinx.collections.immutable.toImmutableMap + +internal class SmileIDBiometricKYC private constructor( + context: Context, + viewId: Int, + messenger: BinaryMessenger, + args: Map, +) : SmileComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { + companion object { + const val VIEW_TYPE_ID = "SmileIDBiometricKYC" + } + + @Composable + override fun Content(args: Map) { + val extraPartnerParams = args["extraPartnerParams"] as? Map ?: emptyMap() + SmileID.BiometricKYC( + idInfo = + IdInfo( + country = args["country"] as? String ?: "", + idType = args["idType"] as? String?, + idNumber = args["idNumber"] as? String?, + firstName = args["firstName"] as? String?, + middleName = args["middleName"] as? String?, + lastName = args["lastName"] as? String?, + dob = args["dob"] as? String?, + bankCode = args["bankCode"] as? String?, + entered = args["entered"] as? Boolean?, + ), + consentInformation = + ConsentInformation( + consented = ConsentedInformation( + consentGrantedDate = args["consentGrantedDate"] as? String + ?: getCurrentIsoTimestamp(), + personalDetails = args["personalDetailsConsentGranted"] as? Boolean == true, + contactInformation = args["contactInfoConsentGranted"] as? Boolean == true, + documentInformation = args["documentInfoConsentGranted"] as? Boolean == true, + ), + ), + userId = args["userId"] as? String ?: randomUserId(), + jobId = args["jobId"] as? String ?: randomJobId(), + allowNewEnroll = args["allowNewEnroll"] as? Boolean ?: false, + allowAgentMode = args["allowAgentMode"] as? Boolean ?: false, + showAttribution = args["showAttribution"] as? Boolean ?: true, + showInstructions = args["showInstructions"] as? Boolean ?: true, + useStrictMode = args["useStrictMode"] as? Boolean ?: true, + extraPartnerParams = extraPartnerParams.toImmutableMap(), + ) { + when (it) { + is SmileIDResult.Success -> { + val result = + SmartSelfieCaptureResult( + selfieFile = it.data.selfieFile, + livenessFiles = it.data.livenessFiles, + didSubmitBiometricKycJob = it.data.didSubmitBiometricKycJob, + ) + val moshi = + SmileID.moshi + .newBuilder() + .add(SelfieCaptureResultAdapter.FACTORY) + .build() + val json = + try { + moshi + .adapter(SmartSelfieCaptureResult::class.java) + .toJson(result) + } catch (e: Exception) { + onError(e) + return@BiometricKYC + } + json?.let { js -> + onSuccessJson(js) + } + } + + is SmileIDResult.Error -> onError(it.throwable) + } + } + } + + class Factory(private val messenger: BinaryMessenger) : + PlatformViewFactory(StandardMessageCodec.INSTANCE) { + override fun create(context: Context, viewId: Int, args: Any?): PlatformView { + @Suppress("UNCHECKED_CAST") + return SmileIDBiometricKYC( + context, + viewId, + messenger, + args as Map, + ) + } + } +} diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentCaptureView.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentCaptureView.kt new file mode 100644 index 0000000..7570247 --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentCaptureView.kt @@ -0,0 +1,153 @@ +package com.smileidentity.flutter + +import android.content.Context +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import com.smileidentity.R +import com.smileidentity.SmileID +import com.smileidentity.compose.document.DocumentCaptureScreen +import com.smileidentity.compose.document.DocumentCaptureSide +import com.smileidentity.compose.theme.colorScheme +import com.smileidentity.compose.theme.typography +import com.smileidentity.flutter.results.DocumentCaptureResult +import com.smileidentity.flutter.utils.DocumentCaptureResultAdapter +import com.smileidentity.util.randomJobId +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.StandardMessageCodec +import io.flutter.plugin.platform.PlatformView +import io.flutter.plugin.platform.PlatformViewFactory +import java.io.File + +internal class SmileIDDocumentCaptureView private constructor( + context: Context, + viewId: Int, + messenger: BinaryMessenger, + args: Map, +) : SmileComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { + companion object { + const val VIEW_TYPE_ID = "SmileIDDocumentCaptureView" + } + + @Composable + override fun Content(args: Map) { + MaterialTheme( + colorScheme = SmileID.colorScheme, + typography = SmileID.typography, + ) { + Surface( + modifier = Modifier.fillMaxSize(), + ) { + val isDocumentFrontSide = args["isDocumentFrontSide"] as? Boolean ?: true + val showInstructions = args["showInstructions"] as? Boolean ?: true + val showAttribution = args["showAttribution"] as? Boolean ?: true + val allowGalleryUpload = args["allowGalleryUpload"] as? Boolean ?: false + val showConfirmationDialog = args["showConfirmationDialog"] as? Boolean ?: true + val idAspectRatio = (args["idAspectRatio"] as Double?)?.toFloat() + RenderDocumentCaptureScreen( + jobId = randomJobId(), + isDocumentFrontSide = isDocumentFrontSide, + showInstructions = showInstructions, + showAttribution = showAttribution, + allowGalleryUpload = allowGalleryUpload, + showConfirmationDialog = showConfirmationDialog, + idAspectRatio = idAspectRatio, + ) + } + } + } + + @Composable + private fun RenderDocumentCaptureScreen( + jobId: String, + isDocumentFrontSide: Boolean, + showInstructions: Boolean, + showAttribution: Boolean, + allowGalleryUpload: Boolean, + showConfirmationDialog: Boolean, + idAspectRatio: Float?, + ) { + val hero = + if (isDocumentFrontSide) { + R.drawable.si_doc_v_front_hero + } else { + R.drawable.si_doc_v_back_hero + } + val instructionTitle = + if (isDocumentFrontSide) { + R.string.si_doc_v_instruction_title + } else { + R.string.si_doc_v_instruction_back_title + } + val instructionSubTitle = + if (isDocumentFrontSide) { + R.string.si_verify_identity_instruction_subtitle + } else { + R.string.si_doc_v_instruction_back_subtitle + } + val captureTitleText = + if (isDocumentFrontSide) { + R.string.si_doc_v_capture_instructions_front_title + } else { + R.string.si_doc_v_capture_instructions_back_title + } + DocumentCaptureScreen( + jobId = jobId, + side = if (isDocumentFrontSide) DocumentCaptureSide.Front else DocumentCaptureSide.Back, + showInstructions = showInstructions, + showAttribution = showAttribution, + allowGallerySelection = allowGalleryUpload, + showConfirmation = showConfirmationDialog, + showSkipButton = false, + instructionsHeroImage = hero, + instructionsTitleText = stringResource(instructionTitle), + instructionsSubtitleText = stringResource(instructionSubTitle), + captureTitleText = stringResource(captureTitleText), + knownIdAspectRatio = idAspectRatio, + onConfirm = { file -> handleConfirmation(isDocumentFrontSide, file) }, + onError = { throwable -> onError(throwable) }, + onSkip = { }, + ) + } + + private fun handleConfirmation(isDocumentFrontSide: Boolean, file: File) { + val moshi = + SmileID.moshi + .newBuilder() + .add(DocumentCaptureResultAdapter.FACTORY) + .build() + val result = + DocumentCaptureResult( + documentFrontFile = if (isDocumentFrontSide) file else null, + documentBackFile = if (!isDocumentFrontSide) file else null, + ) + val json = + try { + moshi + .adapter(DocumentCaptureResult::class.java) + .toJson(result) + } catch (e: Exception) { + onError(e) + return + } + json?.let { + onSuccessJson(it) + } + } + + class Factory(private val messenger: BinaryMessenger) : + PlatformViewFactory(StandardMessageCodec.INSTANCE) { + override fun create(context: Context, viewId: Int, args: Any?): PlatformView { + @Suppress("UNCHECKED_CAST") + return SmileIDDocumentCaptureView( + context, + viewId, + messenger, + args as Map, + ) + } + } +} diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentVerification.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentVerification.kt new file mode 100644 index 0000000..25717ae --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentVerification.kt @@ -0,0 +1,96 @@ +package com.smileidentity.flutter + +import android.content.Context +import androidx.compose.runtime.Composable +import com.smileidentity.SmileID +import com.smileidentity.compose.DocumentVerification +import com.smileidentity.flutter.results.DocumentCaptureResult +import com.smileidentity.flutter.utils.DocumentCaptureResultAdapter +import com.smileidentity.results.SmileIDResult +import com.smileidentity.util.randomJobId +import com.smileidentity.util.randomUserId +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.StandardMessageCodec +import io.flutter.plugin.platform.PlatformView +import io.flutter.plugin.platform.PlatformViewFactory +import java.io.File +import kotlinx.collections.immutable.toImmutableMap + +internal class SmileIDDocumentVerification private constructor( + context: Context, + viewId: Int, + messenger: BinaryMessenger, + args: Map, +) : SmileComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { + companion object { + const val VIEW_TYPE_ID = "SmileIDDocumentVerification" + } + + @Composable + override fun Content(args: Map) { + val extraPartnerParams = args["extraPartnerParams"] as? Map ?: emptyMap() + SmileID.DocumentVerification( + countryCode = args["countryCode"] as String, + documentType = args["documentType"] as? String, + idAspectRatio = (args["idAspectRatio"] as Double?)?.toFloat(), + captureBothSides = args["captureBothSides"] as? Boolean ?: true, + bypassSelfieCaptureWithFile = + (args["bypassSelfieCaptureWithFile"] as? String)?.let { + File(it) + }, + userId = args["userId"] as? String ?: randomUserId(), + jobId = args["jobId"] as? String ?: randomJobId(), + allowNewEnroll = args["allowNewEnroll"] as? Boolean ?: false, + showAttribution = args["showAttribution"] as? Boolean ?: true, + allowAgentMode = args["allowAgentMode"] as? Boolean ?: false, + allowGalleryUpload = args["allowGalleryUpload"] as? Boolean ?: false, + showInstructions = args["showInstructions"] as? Boolean ?: true, + useStrictMode = args["useStrictMode"] as? Boolean ?: false, + extraPartnerParams = extraPartnerParams.toImmutableMap(), + ) { + when (it) { + is SmileIDResult.Success -> { + val result = + DocumentCaptureResult( + selfieFile = it.data.selfieFile, + documentFrontFile = it.data.documentFrontFile, + livenessFiles = it.data.livenessFiles, + documentBackFile = it.data.documentBackFile, + didSubmitDocumentVerificationJob = + it.data.didSubmitDocumentVerificationJob, + ) + val moshi = + SmileID.moshi + .newBuilder() + .add(DocumentCaptureResultAdapter.FACTORY) + .build() + val json = + try { + moshi.adapter(DocumentCaptureResult::class.java).toJson(result) + } catch (e: Exception) { + onError(e) + return@DocumentVerification + } + json?.let { js -> + onSuccessJson(js) + } + } + + is SmileIDResult.Error -> onError(it.throwable) + } + } + } + + class Factory(private val messenger: BinaryMessenger) : + PlatformViewFactory(StandardMessageCodec.INSTANCE) { + override fun create(context: Context, viewId: Int, args: Any?): PlatformView { + @Suppress("UNCHECKED_CAST") + return SmileIDDocumentVerification( + context, + viewId, + messenger, + args as Map, + ) + } + } +} diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDEnhancedDocumentVerification.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDEnhancedDocumentVerification.kt new file mode 100644 index 0000000..403a986 --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDEnhancedDocumentVerification.kt @@ -0,0 +1,105 @@ +package com.smileidentity.flutter + +import android.content.Context +import androidx.compose.runtime.Composable +import com.smileidentity.SmileID +import com.smileidentity.compose.EnhancedDocumentVerificationScreen +import com.smileidentity.flutter.results.DocumentCaptureResult +import com.smileidentity.flutter.utils.DocumentCaptureResultAdapter +import com.smileidentity.flutter.utils.getCurrentIsoTimestamp +import com.smileidentity.models.ConsentInformation +import com.smileidentity.models.ConsentedInformation +import com.smileidentity.results.SmileIDResult +import com.smileidentity.util.randomJobId +import com.smileidentity.util.randomUserId +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.StandardMessageCodec +import io.flutter.plugin.platform.PlatformView +import io.flutter.plugin.platform.PlatformViewFactory +import kotlinx.collections.immutable.toImmutableMap + +internal class SmileIDEnhancedDocumentVerification private constructor( + context: Context, + viewId: Int, + messenger: BinaryMessenger, + args: Map, +) : SmileComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { + companion object { + const val VIEW_TYPE_ID = "SmileIDEnhancedDocumentVerification" + } + + @Composable + override fun Content(args: Map) { + val extraPartnerParams = args["extraPartnerParams"] as? Map ?: emptyMap() + SmileID.EnhancedDocumentVerificationScreen( + countryCode = args["countryCode"] as String, + documentType = args["documentType"] as? String, + idAspectRatio = (args["idAspectRatio"] as Double?)?.toFloat(), + captureBothSides = args["captureBothSides"] as? Boolean ?: true, + userId = args["userId"] as? String ?: randomUserId(), + jobId = args["jobId"] as? String ?: randomJobId(), + allowNewEnroll = args["allowNewEnroll"] as? Boolean ?: false, + showAttribution = args["showAttribution"] as? Boolean ?: true, + allowAgentMode = args["allowAgentMode"] as? Boolean ?: false, + allowGalleryUpload = args["allowGalleryUpload"] as? Boolean ?: false, + showInstructions = args["showInstructions"] as? Boolean ?: true, + useStrictMode = args["useStrictMode"] as? Boolean ?: false, + consentInformation = + ConsentInformation( + consented = ConsentedInformation( + consentGrantedDate = args["consentGrantedDate"] as? String + ?: getCurrentIsoTimestamp(), + personalDetails = args["personalDetailsConsentGranted"] as? Boolean == true, + contactInformation = args["contactInfoConsentGranted"] as? Boolean == true, + documentInformation = args["documentInfoConsentGranted"] as? Boolean == true, + ), + ), + extraPartnerParams = extraPartnerParams.toImmutableMap(), + ) { + when (it) { + is SmileIDResult.Success -> { + val result = + DocumentCaptureResult( + selfieFile = it.data.selfieFile, + documentFrontFile = it.data.documentFrontFile, + livenessFiles = it.data.livenessFiles, + documentBackFile = it.data.documentBackFile, + didSubmitEnhancedDocVJob = it.data.didSubmitEnhancedDocVJob, + ) + val moshi = + SmileID.moshi + .newBuilder() + .add(DocumentCaptureResultAdapter.FACTORY) + .build() + val json = + try { + moshi + .adapter(DocumentCaptureResult::class.java) + .toJson(result) + } catch (e: Exception) { + onError(e) + return@EnhancedDocumentVerificationScreen + } + json?.let { js -> + onSuccessJson(js) + } + } + + is SmileIDResult.Error -> onError(it.throwable) + } + } + } + + class Factory(private val messenger: BinaryMessenger) : + PlatformViewFactory(StandardMessageCodec.INSTANCE) { + override fun create(context: Context, viewId: Int, args: Any?): PlatformView { + @Suppress("UNCHECKED_CAST") + return SmileIDEnhancedDocumentVerification( + context, + viewId, + messenger, + args as Map, + ) + } + } +} diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt new file mode 100644 index 0000000..41fcb42 --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt @@ -0,0 +1,470 @@ +package com.smileidentity.flutter + +import FlutterAuthenticationRequest +import FlutterAuthenticationResponse +import FlutterBiometricKycJobStatusResponse +import FlutterConfig +import FlutterDocumentVerificationJobStatusResponse +import FlutterEnhancedDocumentVerificationJobStatusResponse +import FlutterEnhancedKycAsyncResponse +import FlutterEnhancedKycRequest +import FlutterEnhancedKycResponse +import FlutterJobStatusRequest +import FlutterPrepUploadRequest +import FlutterPrepUploadResponse +import FlutterProductsConfigRequest +import FlutterProductsConfigResponse +import FlutterServicesResponse +import FlutterSmartSelfieJobStatusResponse +import FlutterSmartSelfieResponse +import FlutterUploadRequest +import FlutterValidDocumentsResponse +import SmileIDApi +import android.app.Activity +import android.content.Context +import com.smileidentity.SmileID +import com.smileidentity.SmileIDOptIn +import com.smileidentity.flutter.enhanced.SmileIDSmartSelfieAuthenticationEnhanced +import com.smileidentity.flutter.enhanced.SmileIDSmartSelfieEnrollmentEnhanced +import com.smileidentity.metadata.models.WrapperSdkName +import com.smileidentity.networking.asFormDataPart +import com.smileidentity.networking.pollBiometricKycJobStatus +import com.smileidentity.networking.pollDocumentVerificationJobStatus +import com.smileidentity.networking.pollEnhancedDocumentVerificationJobStatus +import com.smileidentity.networking.pollSmartSelfieJobStatus +import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.embedding.engine.plugins.activity.ActivityAware +import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding +import java.io.File +import java.net.URL +import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds +import kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.single +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class SmileIDPlugin : + FlutterPlugin, + SmileIDApi, + ActivityAware { + private var activity: Activity? = null + private lateinit var appContext: Context + private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO) + + override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + SmileIDApi.setUp(flutterPluginBinding.binaryMessenger, this) + appContext = flutterPluginBinding.applicationContext + + // Set wrapper info for Flutter SDK + SmileID.setWrapperInfo(WrapperSdkName.Flutter, "11.0.0") + + flutterPluginBinding.platformViewRegistry.registerViewFactory( + SmileIDDocumentVerification.VIEW_TYPE_ID, + SmileIDDocumentVerification.Factory(flutterPluginBinding.binaryMessenger), + ) + + flutterPluginBinding.platformViewRegistry.registerViewFactory( + SmileIDSmartSelfieEnrollment.VIEW_TYPE_ID, + SmileIDSmartSelfieEnrollment.Factory(flutterPluginBinding.binaryMessenger), + ) + + flutterPluginBinding.platformViewRegistry.registerViewFactory( + SmileIDSmartSelfieAuthentication.VIEW_TYPE_ID, + SmileIDSmartSelfieAuthentication.Factory(flutterPluginBinding.binaryMessenger), + ) + + flutterPluginBinding.platformViewRegistry.registerViewFactory( + SmileIDSmartSelfieEnrollmentEnhanced.VIEW_TYPE_ID, + SmileIDSmartSelfieEnrollmentEnhanced.Factory(flutterPluginBinding.binaryMessenger), + ) + + flutterPluginBinding.platformViewRegistry.registerViewFactory( + SmileIDSmartSelfieAuthenticationEnhanced.VIEW_TYPE_ID, + SmileIDSmartSelfieAuthenticationEnhanced.Factory(flutterPluginBinding.binaryMessenger), + ) + + flutterPluginBinding.platformViewRegistry.registerViewFactory( + SmileIDBiometricKYC.VIEW_TYPE_ID, + SmileIDBiometricKYC.Factory(flutterPluginBinding.binaryMessenger), + ) + + flutterPluginBinding.platformViewRegistry.registerViewFactory( + SmileIDEnhancedDocumentVerification.VIEW_TYPE_ID, + SmileIDEnhancedDocumentVerification.Factory(flutterPluginBinding.binaryMessenger), + ) + + flutterPluginBinding.platformViewRegistry.registerViewFactory( + SmileIDSmartSelfieCaptureView.VIEW_TYPE_ID, + SmileIDSmartSelfieCaptureView.Factory(flutterPluginBinding.binaryMessenger), + ) + + flutterPluginBinding.platformViewRegistry.registerViewFactory( + SmileIDDocumentCaptureView.VIEW_TYPE_ID, + SmileIDDocumentCaptureView.Factory(flutterPluginBinding.binaryMessenger), + ) + } + + override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { + SmileIDApi.setUp(binding.binaryMessenger, null) + } + + override fun initializeWithApiKey( + apiKey: String, + config: FlutterConfig, + useSandbox: Boolean, + enableCrashReporting: Boolean, + ) { + SmileID.initialize( + context = appContext, + apiKey = apiKey, + config = config.toRequest(), + useSandbox = useSandbox, + enableCrashReporting = false, + ) + } + + override fun initializeWithConfig( + config: FlutterConfig, + useSandbox: Boolean, + enableCrashReporting: Boolean, + ) { + SmileID.initialize( + context = appContext, + config = config.toRequest(), + useSandbox = useSandbox, + enableCrashReporting = false, + ) + } + + override fun initialize(useSandbox: Boolean) { + SmileID.initialize( + context = appContext, + useSandbox = useSandbox, + ) + } + + override fun setCallbackUrl(callbackUrl: String) { + SmileID.setCallbackUrl(callbackUrl = URL(callbackUrl)) + } + + override fun setAllowOfflineMode(allowOfflineMode: Boolean) { + SmileID.setAllowOfflineMode(allowOfflineMode = allowOfflineMode) + } + + override fun getSubmittedJobs(): List = SmileID.getSubmittedJobs() + + override fun getUnsubmittedJobs(): List = SmileID.getUnsubmittedJobs() + + override fun cleanup(jobId: String) { + SmileID.cleanup(jobId = jobId) + } + + override fun cleanupJobs(jobIds: List) { + SmileID.cleanup(jobIds = jobIds) + } + + override fun submitJob(jobId: String, deleteFilesOnSuccess: Boolean) { + scope.launch { + SmileID.submitJob(jobId = jobId, deleteFilesOnSuccess = deleteFilesOnSuccess) + } + } + + override fun authenticate( + request: FlutterAuthenticationRequest, + callback: (Result) -> Unit, + ) = launch( + work = { SmileID.api.authenticate(request.toRequest()).toResponse() }, + callback = callback, + ) + + override fun prepUpload( + request: FlutterPrepUploadRequest, + callback: (Result) -> Unit, + ) = launch( + work = { SmileID.api.prepUpload(request.toRequest()).toResponse() }, + callback = callback, + ) + + override fun upload( + url: String, + request: FlutterUploadRequest, + callback: (Result) -> Unit, + ) = launch( + work = { SmileID.api.upload(url, request.toRequest()) }, + callback = callback, + ) + + override fun doEnhancedKyc( + request: FlutterEnhancedKycRequest, + callback: (Result) -> Unit, + ) = launch( + work = { SmileID.api.doEnhancedKyc(request.toRequest()).toResponse() }, + callback = callback, + ) + + override fun doEnhancedKycAsync( + request: FlutterEnhancedKycRequest, + callback: (Result) -> Unit, + ) = launch( + work = { SmileID.api.doEnhancedKycAsync(request.toRequest()).toResponse() }, + callback = callback, + ) + + override fun getSmartSelfieJobStatus( + request: FlutterJobStatusRequest, + callback: (Result) -> Unit, + ) = launch( + work = { SmileID.api.getSmartSelfieJobStatus(request.toRequest()).toResponse() }, + callback = callback, + ) + + @OptIn(SmileIDOptIn::class) + override fun doSmartSelfieEnrollment( + signature: String, + timestamp: String, + selfieImage: String, + livenessImages: List, + userId: String, + partnerParams: Map?, + callbackUrl: String?, + sandboxResult: Long?, + allowNewEnroll: Boolean?, + callback: (Result) -> Unit, + ) = launch( + work = { + SmileID.api + .doSmartSelfieEnrollment( + userId = userId, + selfieImage = + File(selfieImage).asFormDataPart( + partName = "selfie_image", + mediaType = "image/jpeg", + ), + livenessImages = + livenessImages.map { + File(selfieImage).asFormDataPart( + partName = "liveness_images", + mediaType = "image/jpeg", + ) + }, + partnerParams = convertNullableMapToNonNull(partnerParams), + callbackUrl = callbackUrl, + sandboxResult = sandboxResult?.toInt(), + allowNewEnroll = allowNewEnroll, + ).toResponse() + }, + callback = callback, + ) + + @OptIn(SmileIDOptIn::class) + override fun doSmartSelfieAuthentication( + signature: String, + timestamp: String, + selfieImage: String, + livenessImages: List, + userId: String, + partnerParams: Map?, + callbackUrl: String?, + sandboxResult: Long?, + callback: (Result) -> Unit, + ) = launch( + work = { + SmileID.api + .doSmartSelfieAuthentication( + userId = userId, + selfieImage = + File(selfieImage).asFormDataPart( + partName = "selfie_image", + mediaType = "image/jpeg", + ), + livenessImages = + livenessImages.map { + File(selfieImage).asFormDataPart( + partName = "liveness_images", + mediaType = "image/jpeg", + ) + }, + partnerParams = convertNullableMapToNonNull(partnerParams), + callbackUrl = callbackUrl, + sandboxResult = sandboxResult?.toInt(), + ).toResponse() + }, + callback = callback, + ) + + override fun getDocumentVerificationJobStatus( + request: FlutterJobStatusRequest, + callback: (Result) -> Unit, + ) = launch( + work = { SmileID.api.getDocumentVerificationJobStatus(request.toRequest()).toResponse() }, + callback = callback, + ) + + override fun getBiometricKycJobStatus( + request: FlutterJobStatusRequest, + callback: (Result) -> Unit, + ) = launch( + work = { SmileID.api.getBiometricKycJobStatus(request.toRequest()).toResponse() }, + callback = callback, + ) + + override fun getEnhancedDocumentVerificationJobStatus( + request: FlutterJobStatusRequest, + callback: (Result) -> Unit, + ) = launch( + work = { + SmileID.api.getEnhancedDocumentVerificationJobStatus(request.toRequest()).toResponse() + }, + callback = callback, + ) + + override fun getProductsConfig( + request: FlutterProductsConfigRequest, + callback: (Result) -> Unit, + ) = launch( + work = { SmileID.api.getProductsConfig(request.toRequest()).toResponse() }, + callback = callback, + ) + + override fun getValidDocuments( + request: FlutterProductsConfigRequest, + callback: (Result) -> Unit, + ) = launch( + work = { SmileID.api.getValidDocuments(request.toRequest()).toResponse() }, + callback = callback, + ) + + override fun getServices(callback: (Result) -> Unit) = launch( + work = { SmileID.api.getServices().toResponse() }, + callback = callback, + ) + + override fun pollSmartSelfieJobStatus( + request: FlutterJobStatusRequest, + interval: Long, + numAttempts: Long, + callback: (Result) -> Unit, + ) = launch( + work = { + pollJobStatus( + apiCall = SmileID.api::pollSmartSelfieJobStatus, + request = request.toRequest(), + interval = interval, + numAttempts = numAttempts, + transform = { it.toResponse() }, + ) + }, + callback = callback, + ) + + override fun pollDocumentVerificationJobStatus( + request: FlutterJobStatusRequest, + interval: Long, + numAttempts: Long, + callback: (Result) -> Unit, + ) = launch( + work = { + pollJobStatus( + apiCall = SmileID.api::pollDocumentVerificationJobStatus, + request = request.toRequest(), + interval = interval, + numAttempts = numAttempts, + transform = { it.toResponse() }, + ) + }, + callback = callback, + ) + + override fun pollBiometricKycJobStatus( + request: FlutterJobStatusRequest, + interval: Long, + numAttempts: Long, + callback: (Result) -> Unit, + ) = launch( + work = { + pollJobStatus( + apiCall = SmileID.api::pollBiometricKycJobStatus, + request = request.toRequest(), + interval = interval, + numAttempts = numAttempts, + transform = { it.toResponse() }, + ) + }, + callback = callback, + ) + + override fun pollEnhancedDocumentVerificationJobStatus( + request: FlutterJobStatusRequest, + interval: Long, + numAttempts: Long, + callback: (Result) -> Unit, + ) = launch( + work = { + pollJobStatus( + apiCall = SmileID.api::pollEnhancedDocumentVerificationJobStatus, + request = request.toRequest(), + interval = interval, + numAttempts = numAttempts, + transform = { it.toResponse() }, + ) + }, + callback = callback, + ) + + private suspend fun pollJobStatus( + apiCall: suspend (RequestType, Duration, Int) -> Flow, + request: RequestType, + interval: Long, + numAttempts: Long, + transform: (ResponseType) -> FlutterResponseType, + ): FlutterResponseType = try { + val response = + withContext(Dispatchers.IO) { + apiCall(request, interval.milliseconds, numAttempts.toInt()) + .map { transform(it) } + .single() + } + response + } catch (e: Exception) { + throw e + } + + /** + * https://stackoverflow.com/a/62206235 + * + * We can get the context in a ActivityAware way, without asking users to pass the context when + * calling "initialize" on the sdk + */ + override fun onAttachedToActivity(binding: ActivityPluginBinding) { + this.activity = binding.activity + } + + override fun onDetachedFromActivityForConfigChanges() {} + + override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {} + + override fun onDetachedFromActivity() {} +} + +/** + * Launches a new coroutine in the specified dispatcher (IO by default) and returns the result to + * the callback. Used for launching coroutines from Dart. + */ +private fun launch( + work: suspend () -> T, + callback: (Result) -> Unit, + scope: CoroutineScope = CoroutineScope(Dispatchers.IO), +) { + val handler = + CoroutineExceptionHandler { _, throwable -> + callback.invoke(Result.failure(throwable)) + } + scope.launch(handler) { + callback.invoke(Result.success(work())) + } +} diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieAuthentication.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieAuthentication.kt new file mode 100644 index 0000000..563877c --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieAuthentication.kt @@ -0,0 +1,51 @@ +package com.smileidentity.flutter + +import android.content.Context +import androidx.compose.runtime.Composable +import com.smileidentity.SmileID +import com.smileidentity.compose.SmartSelfieAuthentication +import com.smileidentity.util.randomUserId +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.StandardMessageCodec +import io.flutter.plugin.platform.PlatformView +import io.flutter.plugin.platform.PlatformViewFactory +import kotlinx.collections.immutable.toImmutableMap + +internal class SmileIDSmartSelfieAuthentication private constructor( + context: Context, + viewId: Int, + messenger: BinaryMessenger, + args: Map, +) : SmileSelfieComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { + companion object { + const val VIEW_TYPE_ID = "SmileIDSmartSelfieAuthentication" + } + + @Composable + override fun Content(args: Map) { + val extraPartnerParams = args["extraPartnerParams"] as? Map ?: emptyMap() + SmileID.SmartSelfieAuthentication( + userId = args["userId"] as? String ?: randomUserId(), + allowNewEnroll = args["allowNewEnroll"] as? Boolean ?: false, + allowAgentMode = args["allowAgentMode"] as? Boolean ?: false, + showAttribution = args["showAttribution"] as? Boolean ?: true, + showInstructions = args["showInstructions"] as? Boolean ?: true, + skipApiSubmission = args["skipApiSubmission"] as? Boolean ?: false, + extraPartnerParams = extraPartnerParams.toImmutableMap(), + onResult = { res -> handleResult(res) }, + ) + } + + class Factory(private val messenger: BinaryMessenger) : + PlatformViewFactory(StandardMessageCodec.INSTANCE) { + override fun create(context: Context, viewId: Int, args: Any?): PlatformView { + @Suppress("UNCHECKED_CAST") + return SmileIDSmartSelfieAuthentication( + context, + viewId, + messenger, + args as Map, + ) + } + } +} diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieCaptureView.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieCaptureView.kt new file mode 100644 index 0000000..b644b24 --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieCaptureView.kt @@ -0,0 +1,197 @@ +package com.smileidentity.flutter + +import android.content.Context +import android.graphics.BitmapFactory +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.consumeWindowInsets +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.statusBars +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.graphics.painter.BitmapPainter +import androidx.compose.ui.res.stringResource +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.viewmodel.compose.viewModel +import com.smileidentity.R +import com.smileidentity.SmileID +import com.smileidentity.SmileIDOptIn +import com.smileidentity.compose.SmartSelfieEnrollmentEnhanced +import com.smileidentity.compose.components.ImageCaptureConfirmationDialog +import com.smileidentity.compose.selfie.SelfieCaptureScreen +import com.smileidentity.compose.selfie.SmartSelfieInstructionsScreen +import com.smileidentity.compose.theme.colorScheme +import com.smileidentity.compose.theme.typography +import com.smileidentity.util.randomJobId +import com.smileidentity.util.randomUserId +import com.smileidentity.viewmodel.SelfieUiState +import com.smileidentity.viewmodel.SelfieViewModel +import com.smileidentity.viewmodel.viewModelFactory +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.StandardMessageCodec +import io.flutter.plugin.platform.PlatformView +import io.flutter.plugin.platform.PlatformViewFactory + +internal class SmileIDSmartSelfieCaptureView private constructor( + context: Context, + viewId: Int, + messenger: BinaryMessenger, + args: Map, +) : SmileSelfieComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { + companion object { + const val VIEW_TYPE_ID = "SmileIDSmartSelfieCaptureView" + } + + @OptIn(SmileIDOptIn::class) + @Composable + override fun Content(args: Map) { + val showConfirmationDialog = args["showConfirmationDialog"] as? Boolean ?: true + val showInstructions = args["showInstructions"] as? Boolean ?: true + val showAttribution = args["showAttribution"] as? Boolean ?: true + val allowAgentMode = args["allowAgentMode"] as? Boolean ?: true + val useStrictMode = args["useStrictMode"] as? Boolean ?: false + var acknowledgedInstructions by rememberSaveable { mutableStateOf(false) } + val userId = randomUserId() + val jobId = randomJobId() + + MaterialTheme(colorScheme = SmileID.colorScheme, typography = SmileID.typography) { + Surface( + content = { + if (useStrictMode) { + // Enhanced mode doesn't support confirmation dialog + SmileID.SmartSelfieEnrollmentEnhanced( + userId = userId, + showAttribution = showAttribution, + showInstructions = showInstructions, + skipApiSubmission = true, + onResult = { res -> handleResult(res) }, + ) + } else { + // Custom implementation for regular mode with confirmation dialog support + val viewModel: SelfieViewModel = viewModel( + factory = viewModelFactory { + SelfieViewModel( + isEnroll = true, + userId = userId, + jobId = jobId, + allowNewEnroll = true, + skipApiSubmission = true, + metadata = mutableListOf(), + ) + }, + ) + + val uiState = viewModel.uiState.collectAsStateWithLifecycle().value + + when { + showInstructions && !acknowledgedInstructions -> + SmartSelfieInstructionsScreen( + showAttribution = showAttribution, + ) { + acknowledgedInstructions = true + } + uiState.processingState != null -> HandleProcessingState(viewModel) + uiState.selfieToConfirm != null -> + HandleSelfieConfirmation( + showConfirmationDialog, + uiState, + viewModel, + ) + else -> RenderSelfieCaptureScreen( + userId, + jobId, + allowAgentMode, + viewModel, + ) + } + } + }, + ) + } + } + + @Composable + private fun RenderSelfieCaptureScreen( + userId: String, + jobId: String, + allowAgentMode: Boolean, + viewModel: SelfieViewModel, + ) { + Box( + modifier = Modifier + .background(color = Color.White) + .windowInsetsPadding(WindowInsets.statusBars) + .consumeWindowInsets(WindowInsets.statusBars) + .fillMaxSize(), + ) { + SelfieCaptureScreen( + userId = userId, + jobId = jobId, + allowAgentMode = allowAgentMode, + allowNewEnroll = true, + skipApiSubmission = true, + viewModel = viewModel, + ) + } + } + + @Composable + private fun HandleSelfieConfirmation( + showConfirmation: Boolean, + uiState: SelfieUiState, + viewModel: SelfieViewModel, + ) { + if (showConfirmation) { + ImageCaptureConfirmationDialog( + titleText = stringResource(R.string.si_smart_selfie_confirmation_dialog_title), + subtitleText = stringResource( + R.string.si_smart_selfie_confirmation_dialog_subtitle, + ), + painter = BitmapPainter( + BitmapFactory + .decodeFile(uiState.selfieToConfirm!!.absolutePath) + .asImageBitmap(), + ), + confirmButtonText = stringResource( + R.string.si_smart_selfie_confirmation_dialog_confirm_button, + ), + onConfirm = { viewModel.submitJob() }, + retakeButtonText = stringResource( + R.string.si_smart_selfie_confirmation_dialog_retake_button, + ), + onRetake = viewModel::onSelfieRejected, + scaleFactor = 1.25f, + ) + } else { + viewModel.submitJob() + } + } + + @Composable + private fun HandleProcessingState(viewModel: SelfieViewModel) { + viewModel.onFinished { res -> handleResult(res) } + } + + class Factory(private val messenger: BinaryMessenger) : + PlatformViewFactory(StandardMessageCodec.INSTANCE) { + override fun create(context: Context, viewId: Int, args: Any?): PlatformView { + @Suppress("UNCHECKED_CAST") + return SmileIDSmartSelfieCaptureView( + context, + viewId, + messenger, + args as Map, + ) + } + } +} diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieEnrollment.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieEnrollment.kt new file mode 100644 index 0000000..90aa890 --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieEnrollment.kt @@ -0,0 +1,51 @@ +package com.smileidentity.flutter + +import android.content.Context +import androidx.compose.runtime.Composable +import com.smileidentity.SmileID +import com.smileidentity.compose.SmartSelfieEnrollment +import com.smileidentity.util.randomUserId +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.StandardMessageCodec +import io.flutter.plugin.platform.PlatformView +import io.flutter.plugin.platform.PlatformViewFactory +import kotlinx.collections.immutable.toImmutableMap + +internal class SmileIDSmartSelfieEnrollment private constructor( + context: Context, + viewId: Int, + messenger: BinaryMessenger, + args: Map, +) : SmileSelfieComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { + companion object { + const val VIEW_TYPE_ID = "SmileIDSmartSelfieEnrollment" + } + + @Composable + override fun Content(args: Map) { + val extraPartnerParams = args["extraPartnerParams"] as? Map ?: emptyMap() + SmileID.SmartSelfieEnrollment( + userId = args["userId"] as? String ?: randomUserId(), + allowNewEnroll = args["allowNewEnroll"] as? Boolean ?: false, + allowAgentMode = args["allowAgentMode"] as? Boolean ?: false, + showAttribution = args["showAttribution"] as? Boolean ?: true, + showInstructions = args["showInstructions"] as? Boolean ?: true, + skipApiSubmission = args["skipApiSubmission"] as? Boolean ?: false, + extraPartnerParams = extraPartnerParams.toImmutableMap(), + onResult = { res -> handleResult(res) }, + ) + } + + class Factory(private val messenger: BinaryMessenger) : + PlatformViewFactory(StandardMessageCodec.INSTANCE) { + override fun create(context: Context, viewId: Int, args: Any?): PlatformView { + @Suppress("UNCHECKED_CAST") + return SmileIDSmartSelfieEnrollment( + context, + viewId, + messenger, + args as Map, + ) + } + } +} diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileSelfieComposablePlatformView.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileSelfieComposablePlatformView.kt new file mode 100644 index 0000000..0e69880 --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileSelfieComposablePlatformView.kt @@ -0,0 +1,49 @@ +package com.smileidentity.flutter + +import android.content.Context +import com.smileidentity.SmileID +import com.smileidentity.flutter.results.SmartSelfieCaptureResult +import com.smileidentity.flutter.utils.SelfieCaptureResultAdapter +import com.smileidentity.results.SmartSelfieResult +import com.smileidentity.results.SmileIDResult +import io.flutter.plugin.common.BinaryMessenger + +internal abstract class SmileSelfieComposablePlatformView( + context: Context, + viewTypeId: String, + viewId: Int, + messenger: BinaryMessenger, + args: Map, +) : SmileComposablePlatformView(context, viewTypeId, viewId, messenger, args) { + protected fun handleResult(res: SmileIDResult) { + when (res) { + is SmileIDResult.Success -> { + val result = + SmartSelfieCaptureResult( + selfieFile = res.data.selfieFile, + livenessFiles = res.data.livenessFiles, + apiResponse = res.data.apiResponse, + ) + val moshi = + SmileID.moshi + .newBuilder() + .add(SelfieCaptureResultAdapter.FACTORY) + .build() + val json = + try { + moshi + .adapter(SmartSelfieCaptureResult::class.java) + .toJson(result) + } catch (e: Exception) { + onError(e) + return + } + json?.let { js -> + onSuccessJson(js) + } + } + + is SmileIDResult.Error -> onError(res.throwable) + } + } +} diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieAuthenticationEnhanced.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieAuthenticationEnhanced.kt new file mode 100644 index 0000000..83976ab --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieAuthenticationEnhanced.kt @@ -0,0 +1,51 @@ +package com.smileidentity.flutter.enhanced + +import android.content.Context +import androidx.compose.runtime.Composable +import com.smileidentity.SmileID +import com.smileidentity.compose.SmartSelfieAuthenticationEnhanced +import com.smileidentity.flutter.SmileSelfieComposablePlatformView +import com.smileidentity.util.randomUserId +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.StandardMessageCodec +import io.flutter.plugin.platform.PlatformView +import io.flutter.plugin.platform.PlatformViewFactory +import kotlinx.collections.immutable.toImmutableMap + +internal class SmileIDSmartSelfieAuthenticationEnhanced private constructor( + context: Context, + viewId: Int, + messenger: BinaryMessenger, + args: Map, +) : SmileSelfieComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { + companion object { + const val VIEW_TYPE_ID = "SmileIDSmartSelfieAuthenticationEnhanced" + } + + @Composable + override fun Content(args: Map) { + val extraPartnerParams = args["extraPartnerParams"] as? Map ?: emptyMap() + SmileID.SmartSelfieAuthenticationEnhanced( + userId = args["userId"] as? String ?: randomUserId(), + allowNewEnroll = args["allowNewEnroll"] as? Boolean ?: false, + showAttribution = args["showAttribution"] as? Boolean ?: true, + showInstructions = args["showInstructions"] as? Boolean ?: true, + skipApiSubmission = args["skipApiSubmission"] as? Boolean ?: false, + extraPartnerParams = extraPartnerParams.toImmutableMap(), + onResult = { res -> handleResult(res) }, + ) + } + + class Factory(private val messenger: BinaryMessenger) : + PlatformViewFactory(StandardMessageCodec.INSTANCE) { + override fun create(context: Context, viewId: Int, args: Any?): PlatformView { + @Suppress("UNCHECKED_CAST") + return SmileIDSmartSelfieAuthenticationEnhanced( + context, + viewId, + messenger, + args as Map, + ) + } + } +} diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieEnrollmentEnhanced.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieEnrollmentEnhanced.kt new file mode 100644 index 0000000..d1d08fb --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieEnrollmentEnhanced.kt @@ -0,0 +1,51 @@ +package com.smileidentity.flutter.enhanced + +import android.content.Context +import androidx.compose.runtime.Composable +import com.smileidentity.SmileID +import com.smileidentity.compose.SmartSelfieEnrollmentEnhanced +import com.smileidentity.flutter.SmileSelfieComposablePlatformView +import com.smileidentity.util.randomUserId +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.StandardMessageCodec +import io.flutter.plugin.platform.PlatformView +import io.flutter.plugin.platform.PlatformViewFactory +import kotlinx.collections.immutable.toImmutableMap + +internal class SmileIDSmartSelfieEnrollmentEnhanced private constructor( + context: Context, + viewId: Int, + messenger: BinaryMessenger, + args: Map, +) : SmileSelfieComposablePlatformView(context, VIEW_TYPE_ID, viewId, messenger, args) { + companion object { + const val VIEW_TYPE_ID = "SmileIDSmartSelfieEnrollmentEnhanced" + } + + @Composable + override fun Content(args: Map) { + val extraPartnerParams = args["extraPartnerParams"] as? Map ?: emptyMap() + SmileID.SmartSelfieEnrollmentEnhanced( + userId = args["userId"] as? String ?: randomUserId(), + allowNewEnroll = args["allowNewEnroll"] as? Boolean ?: false, + showAttribution = args["showAttribution"] as? Boolean ?: true, + showInstructions = args["showInstructions"] as? Boolean ?: true, + skipApiSubmission = args["skipApiSubmission"] as? Boolean ?: false, + extraPartnerParams = extraPartnerParams.toImmutableMap(), + onResult = { res -> handleResult(res) }, + ) + } + + class Factory(private val messenger: BinaryMessenger) : + PlatformViewFactory(StandardMessageCodec.INSTANCE) { + override fun create(context: Context, viewId: Int, args: Any?): PlatformView { + @Suppress("UNCHECKED_CAST") + return SmileIDSmartSelfieEnrollmentEnhanced( + context, + viewId, + messenger, + args as Map, + ) + } + } +} diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/generated/SmileIDMessages.g.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/generated/SmileIDMessages.g.kt new file mode 100644 index 0000000..78f17ec --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/generated/SmileIDMessages.g.kt @@ -0,0 +1,2864 @@ +// Autogenerated from Pigeon (v16.0.5), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +import android.util.Log +import io.flutter.plugin.common.BasicMessageChannel +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.MessageCodec +import io.flutter.plugin.common.StandardMessageCodec +import java.io.ByteArrayOutputStream +import java.nio.ByteBuffer + +private fun wrapResult(result: Any?): List = listOf(result) + +private fun wrapError(exception: Throwable): List { + if (exception is SmileFlutterError) { + return listOf( + exception.code, + exception.message, + exception.details, + ) + } else { + return listOf( + exception.javaClass.simpleName, + exception.toString(), + "Cause: " + exception.cause + ", Stacktrace: " + Log.getStackTraceString(exception), + ) + } +} + +/** + * Error class for passing custom error details to Flutter via a thrown PlatformException. + * @property code The error code. + * @property message The error message. + * @property details The error details. Must be a datatype supported by the api codec. + */ +class SmileFlutterError( + val code: String, + override val message: String? = null, + val details: Any? = null, +) : Throwable() + +enum class FlutterJobType(val raw: Int) { + ENHANCEDKYC(0), + DOCUMENTVERIFICATION(1), + BIOMETRICKYC(2), + ENHANCEDDOCUMENTVERIFICATION(3), + SMARTSELFIEENROLLMENT(4), + SMARTSELFIEAUTHENTICATION(5), + ; + + companion object { + fun ofRaw(raw: Int): FlutterJobType? = values().firstOrNull { it.raw == raw } + } +} + +enum class FlutterJobTypeV2(val raw: Int) { + SMARTSELFIEAUTHENTICATION(0), + SMARTSELFIEENROLLMENT(1), + ; + + companion object { + fun ofRaw(raw: Int): FlutterJobTypeV2? = values().firstOrNull { it.raw == raw } + } +} + +enum class FlutterImageType(val raw: Int) { + SELFIEJPGFILE(0), + IDCARDJPGFILE(1), + SELFIEJPGBASE64(2), + IDCARDJPGBASE64(3), + LIVENESSJPGFILE(4), + IDCARDREARJPGFILE(5), + LIVENESSJPGBASE64(6), + IDCARDREARJPGBASE64(7), + ; + + companion object { + fun ofRaw(raw: Int): FlutterImageType? = values().firstOrNull { it.raw == raw } + } +} + +enum class FlutterActionResult(val raw: Int) { + PASSED(0), + COMPLETED(1), + APPROVED(2), + VERIFIED(3), + PROVISIONALLYAPPROVED(4), + RETURNED(5), + NOTRETURNED(6), + FAILED(7), + REJECTED(8), + UNDERREVIEW(9), + UNABLETODETERMINE(10), + NOTAPPLICABLE(11), + NOTVERIFIED(12), + NOTDONE(13), + ISSUERUNAVAILABLE(14), + IDAUTHORITYPHOTONOTAVAILABLE(15), + SENTTOHUMANREVIEW(16), + UNKNOWN(17), + ; + + companion object { + fun ofRaw(raw: Int): FlutterActionResult? = values().firstOrNull { it.raw == raw } + } +} + +enum class FlutterSmartSelfieStatus(val raw: Int) { + APPROVED(0), + PENDING(1), + REJECTED(2), + UNKNOWN(3), + ; + + companion object { + fun ofRaw(raw: Int): FlutterSmartSelfieStatus? = values().firstOrNull { it.raw == raw } + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterConsentInformation( + val consentGrantedDate: String, + val personalDetailsConsentGranted: Boolean, + val contactInfoConsentGranted: Boolean, + val documentInfoConsentGranted: Boolean, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterConsentInformation { + val consentGrantedDate = list[0] as String + val personalDetailsConsentGranted = list[1] as Boolean + val contactInfoConsentGranted = list[2] as Boolean + val documentInfoConsentGranted = list[3] as Boolean + return FlutterConsentInformation( + consentGrantedDate, + personalDetailsConsentGranted, + contactInfoConsentGranted, + documentInfoConsentGranted, + ) + } + } + fun toList(): List = listOf( + consentGrantedDate, + personalDetailsConsentGranted, + contactInfoConsentGranted, + documentInfoConsentGranted, + ) +} + +/** + * Custom values specific to partners can be placed in [extras] + * + * Generated class from Pigeon that represents data sent in messages. + */ +data class FlutterPartnerParams( + val jobType: FlutterJobType? = null, + val jobId: String, + val userId: String, + val extras: Map? = null, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterPartnerParams { + val jobType: FlutterJobType? = (list[0] as Int?)?.let { + FlutterJobType.ofRaw(it) + } + val jobId = list[1] as String + val userId = list[2] as String + val extras = list[3] as Map? + return FlutterPartnerParams(jobType, jobId, userId, extras) + } + } + fun toList(): List = listOf( + jobType?.raw, + jobId, + userId, + extras, + ) +} + +/** + * The Auth Smile request. Auth Smile serves multiple purposes: + * + * - It is used to fetch the signature needed for subsequent API requests + * - It indicates the type of job that will being performed + * - It is used to fetch consent information for the partner + * + * [jobType] The type of job that will be performed + * [country] The country code of the country where the job is being performed. This value is + * required in order to get back consent information for the partner + * [idType] The type of ID that will be used for the job. This value is required in order to + * get back consent information for the partner + * [updateEnrolledImage] Whether or not the enrolled image should be updated with image + * submitted for this job + * [jobId] The job ID to associate with the job. Most often, this will correspond to a unique + * Job ID within your own system. If not provided, a random job ID will be generated + * [userId] The user ID to associate with the job. Most often, this will correspond to a unique + * User ID within your own system. If not provided, a random user ID will be generated + * + * Generated class from Pigeon that represents data sent in messages. + */ +data class FlutterAuthenticationRequest( + val jobType: FlutterJobType, + val country: String? = null, + val idType: String? = null, + val updateEnrolledImage: Boolean? = null, + val jobId: String? = null, + val userId: String? = null, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterAuthenticationRequest { + val jobType = FlutterJobType.ofRaw(list[0] as Int)!! + val country = list[1] as String? + val idType = list[2] as String? + val updateEnrolledImage = list[3] as Boolean? + val jobId = list[4] as String? + val userId = list[5] as String? + return FlutterAuthenticationRequest( + jobType, + country, + idType, + updateEnrolledImage, + jobId, + userId, + ) + } + } + fun toList(): List = listOf( + jobType.raw, + country, + idType, + updateEnrolledImage, + jobId, + userId, + ) +} + +/** + * [consentInfo] is only populated when a country and ID type are provided in the + * [FlutterAuthenticationRequest]. To get information about *all* countries and ID types instead, + * [SmileIDService.getProductsConfig] + * + * [timestamp] is *not* a [DateTime] because technically, any arbitrary value could have been + * passed to it. This applies to all other timestamp fields in the SDK. + * + * Generated class from Pigeon that represents data sent in messages. + */ +data class FlutterAuthenticationResponse( + val success: Boolean, + val signature: String, + val timestamp: String, + val partnerParams: FlutterPartnerParams, + val callbackUrl: String? = null, + val consentInfo: FlutterConsentInfo? = null, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterAuthenticationResponse { + val success = list[0] as Boolean + val signature = list[1] as String + val timestamp = list[2] as String + val partnerParams = FlutterPartnerParams.fromList(list[3] as List) + val callbackUrl = list[4] as String? + val consentInfo: FlutterConsentInfo? = (list[5] as List?)?.let { + FlutterConsentInfo.fromList(it) + } + return FlutterAuthenticationResponse( + success, + signature, + timestamp, + partnerParams, + callbackUrl, + consentInfo, + ) + } + } + fun toList(): List = listOf( + success, + signature, + timestamp, + partnerParams.toList(), + callbackUrl, + consentInfo?.toList(), + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterPrepUploadRequest( + val partnerParams: FlutterPartnerParams, + val callbackUrl: String? = null, + val allowNewEnroll: Boolean, + val partnerId: String, + val timestamp: String, + val signature: String, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterPrepUploadRequest { + val partnerParams = FlutterPartnerParams.fromList(list[0] as List) + val callbackUrl = list[1] as String? + val allowNewEnroll = list[2] as Boolean + val partnerId = list[3] as String + val timestamp = list[4] as String + val signature = list[5] as String + return FlutterPrepUploadRequest( + partnerParams, + callbackUrl, + allowNewEnroll, + partnerId, + timestamp, + signature, + ) + } + } + fun toList(): List = listOf( + partnerParams.toList(), + callbackUrl, + allowNewEnroll, + partnerId, + timestamp, + signature, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterPrepUploadResponse( + val code: String, + val refId: String, + val uploadUrl: String, + val smileJobId: String, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterPrepUploadResponse { + val code = list[0] as String + val refId = list[1] as String + val uploadUrl = list[2] as String + val smileJobId = list[3] as String + return FlutterPrepUploadResponse(code, refId, uploadUrl, smileJobId) + } + } + fun toList(): List = listOf( + code, + refId, + uploadUrl, + smileJobId, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterUploadRequest( + val images: List, + val idInfo: FlutterIdInfo? = null, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterUploadRequest { + val images = list[0] as List + val idInfo: FlutterIdInfo? = (list[1] as List?)?.let { + FlutterIdInfo.fromList(it) + } + return FlutterUploadRequest(images, idInfo) + } + } + fun toList(): List = listOf( + images, + idInfo?.toList(), + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterUploadImageInfo(val imageTypeId: FlutterImageType, val imageName: String) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterUploadImageInfo { + val imageTypeId = FlutterImageType.ofRaw(list[0] as Int)!! + val imageName = list[1] as String + return FlutterUploadImageInfo(imageTypeId, imageName) + } + } + fun toList(): List = listOf( + imageTypeId.raw, + imageName, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterIdInfo( + val country: String, + val idType: String? = null, + val idNumber: String? = null, + val firstName: String? = null, + val middleName: String? = null, + val lastName: String? = null, + val dob: String? = null, + val bankCode: String? = null, + val entered: Boolean? = null, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterIdInfo { + val country = list[0] as String + val idType = list[1] as String? + val idNumber = list[2] as String? + val firstName = list[3] as String? + val middleName = list[4] as String? + val lastName = list[5] as String? + val dob = list[6] as String? + val bankCode = list[7] as String? + val entered = list[8] as Boolean? + return FlutterIdInfo(country, idType, idNumber, firstName, middleName, lastName, dob, bankCode, entered) + } + } + fun toList(): List = listOf( + country, + idType, + idNumber, + firstName, + middleName, + lastName, + dob, + bankCode, + entered, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterEnhancedKycResponse( + val smileJobId: String, + val partnerParams: FlutterPartnerParams, + val resultText: String, + val resultCode: String, + val actions: FlutterActions, + val country: String, + val idType: String, + val idNumber: String, + val fullName: String? = null, + val expirationDate: String? = null, + val dob: String? = null, + val base64Photo: String? = null, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterEnhancedKycResponse { + val smileJobId = list[0] as String + val partnerParams = FlutterPartnerParams.fromList(list[1] as List) + val resultText = list[2] as String + val resultCode = list[3] as String + val actions = FlutterActions.fromList(list[4] as List) + val country = list[5] as String + val idType = list[6] as String + val idNumber = list[7] as String + val fullName = list[8] as String? + val expirationDate = list[9] as String? + val dob = list[10] as String? + val base64Photo = list[11] as String? + return FlutterEnhancedKycResponse(smileJobId, partnerParams, resultText, resultCode, actions, country, idType, idNumber, fullName, expirationDate, dob, base64Photo) + } + } + fun toList(): List = listOf( + smileJobId, + partnerParams.toList(), + resultText, + resultCode, + actions.toList(), + country, + idType, + idNumber, + fullName, + expirationDate, + dob, + base64Photo, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterActions( + val documentCheck: FlutterActionResult, + val humanReviewCompare: FlutterActionResult, + val humanReviewDocumentCheck: FlutterActionResult, + val humanReviewLivenessCheck: FlutterActionResult, + val humanReviewSelfieCheck: FlutterActionResult, + val humanReviewUpdateSelfie: FlutterActionResult, + val livenessCheck: FlutterActionResult, + val registerSelfie: FlutterActionResult, + val returnPersonalInfo: FlutterActionResult, + val selfieCheck: FlutterActionResult, + val selfieProvided: FlutterActionResult, + val selfieToIdAuthorityCompare: FlutterActionResult, + val selfieToIdCardCompare: FlutterActionResult, + val selfieToRegisteredSelfieCompare: FlutterActionResult, + val updateRegisteredSelfieOnFile: FlutterActionResult, + val verifyDocument: FlutterActionResult, + val verifyIdNumber: FlutterActionResult, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterActions { + val documentCheck = FlutterActionResult.ofRaw(list[0] as Int)!! + val humanReviewCompare = FlutterActionResult.ofRaw(list[1] as Int)!! + val humanReviewDocumentCheck = FlutterActionResult.ofRaw(list[2] as Int)!! + val humanReviewLivenessCheck = FlutterActionResult.ofRaw(list[3] as Int)!! + val humanReviewSelfieCheck = FlutterActionResult.ofRaw(list[4] as Int)!! + val humanReviewUpdateSelfie = FlutterActionResult.ofRaw(list[5] as Int)!! + val livenessCheck = FlutterActionResult.ofRaw(list[6] as Int)!! + val registerSelfie = FlutterActionResult.ofRaw(list[7] as Int)!! + val returnPersonalInfo = FlutterActionResult.ofRaw(list[8] as Int)!! + val selfieCheck = FlutterActionResult.ofRaw(list[9] as Int)!! + val selfieProvided = FlutterActionResult.ofRaw(list[10] as Int)!! + val selfieToIdAuthorityCompare = FlutterActionResult.ofRaw(list[11] as Int)!! + val selfieToIdCardCompare = FlutterActionResult.ofRaw(list[12] as Int)!! + val selfieToRegisteredSelfieCompare = FlutterActionResult.ofRaw(list[13] as Int)!! + val updateRegisteredSelfieOnFile = FlutterActionResult.ofRaw(list[14] as Int)!! + val verifyDocument = FlutterActionResult.ofRaw(list[15] as Int)!! + val verifyIdNumber = FlutterActionResult.ofRaw(list[16] as Int)!! + return FlutterActions(documentCheck, humanReviewCompare, humanReviewDocumentCheck, humanReviewLivenessCheck, humanReviewSelfieCheck, humanReviewUpdateSelfie, livenessCheck, registerSelfie, returnPersonalInfo, selfieCheck, selfieProvided, selfieToIdAuthorityCompare, selfieToIdCardCompare, selfieToRegisteredSelfieCompare, updateRegisteredSelfieOnFile, verifyDocument, verifyIdNumber) + } + } + fun toList(): List = listOf( + documentCheck.raw, + humanReviewCompare.raw, + humanReviewDocumentCheck.raw, + humanReviewLivenessCheck.raw, + humanReviewSelfieCheck.raw, + humanReviewUpdateSelfie.raw, + livenessCheck.raw, + registerSelfie.raw, + returnPersonalInfo.raw, + selfieCheck.raw, + selfieProvided.raw, + selfieToIdAuthorityCompare.raw, + selfieToIdCardCompare.raw, + selfieToRegisteredSelfieCompare.raw, + updateRegisteredSelfieOnFile.raw, + verifyDocument.raw, + verifyIdNumber.raw, + ) +} + +/** + * [canAccess] Whether or not the ID type is enabled for the partner + * [consentRequired] Whether or not consent is required for the ID type + * + * Generated class from Pigeon that represents data sent in messages. + */ +data class FlutterConsentInfo(val canAccess: Boolean, val consentRequired: Boolean) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterConsentInfo { + val canAccess = list[0] as Boolean + val consentRequired = list[1] as Boolean + return FlutterConsentInfo(canAccess, consentRequired) + } + } + fun toList(): List = listOf( + canAccess, + consentRequired, + ) +} + +/** + * [timestamp] is *not* a [DateTime] because technically, any arbitrary value could have been + * passed to it. This applies to all other timestamp fields in the SDK. + * + * Generated class from Pigeon that represents data sent in messages. + */ +data class FlutterEnhancedKycRequest( + val country: String, + val idType: String, + val idNumber: String, + val firstName: String? = null, + val middleName: String? = null, + val lastName: String? = null, + val dob: String? = null, + val phoneNumber: String? = null, + val bankCode: String? = null, + val callbackUrl: String? = null, + val partnerParams: FlutterPartnerParams, + val timestamp: String, + val signature: String, + val consentInformation: FlutterConsentInformation? = null, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterEnhancedKycRequest { + val country = list[0] as String + val idType = list[1] as String + val idNumber = list[2] as String + val firstName = list[3] as String? + val middleName = list[4] as String? + val lastName = list[5] as String? + val dob = list[6] as String? + val phoneNumber = list[7] as String? + val bankCode = list[8] as String? + val callbackUrl = list[9] as String? + val partnerParams = FlutterPartnerParams.fromList(list[10] as List) + val timestamp = list[11] as String + val signature = list[12] as String + val consentInformation: FlutterConsentInformation? = (list[13] as List?)?.let { + FlutterConsentInformation.fromList(it) + } + return FlutterEnhancedKycRequest(country, idType, idNumber, firstName, middleName, lastName, dob, phoneNumber, bankCode, callbackUrl, partnerParams, timestamp, signature, consentInformation) + } + } + fun toList(): List = listOf( + country, + idType, + idNumber, + firstName, + middleName, + lastName, + dob, + phoneNumber, + bankCode, + callbackUrl, + partnerParams.toList(), + timestamp, + signature, + consentInformation?.toList(), + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterEnhancedKycAsyncResponse(val success: Boolean) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterEnhancedKycAsyncResponse { + val success = list[0] as Boolean + return FlutterEnhancedKycAsyncResponse(success) + } + } + fun toList(): List = listOf( + success, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterImageLinks(val selfieImageUrl: String? = null, val error: String? = null) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterImageLinks { + val selfieImageUrl = list[0] as String? + val error = list[1] as String? + return FlutterImageLinks(selfieImageUrl, error) + } + } + fun toList(): List = listOf( + selfieImageUrl, + error, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterAntifraud(val suspectUsers: List) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterAntifraud { + val suspectUsers = list[0] as List + return FlutterAntifraud(suspectUsers) + } + } + fun toList(): List = listOf( + suspectUsers, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterSuspectUser(val reason: String, val userId: String) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterSuspectUser { + val reason = list[0] as String + val userId = list[1] as String + return FlutterSuspectUser(reason, userId) + } + } + fun toList(): List = listOf( + reason, + userId, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterJobStatusRequest( + val userId: String, + val jobId: String, + val includeImageLinks: Boolean, + val includeHistory: Boolean, + val partnerId: String, + val timestamp: String, + val signature: String, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterJobStatusRequest { + val userId = list[0] as String + val jobId = list[1] as String + val includeImageLinks = list[2] as Boolean + val includeHistory = list[3] as Boolean + val partnerId = list[4] as String + val timestamp = list[5] as String + val signature = list[6] as String + return FlutterJobStatusRequest( + userId, + jobId, + includeImageLinks, + includeHistory, + partnerId, + timestamp, + signature, + ) + } + } + fun toList(): List = listOf( + userId, + jobId, + includeImageLinks, + includeHistory, + partnerId, + timestamp, + signature, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterSmartSelfieJobResult( + val actions: FlutterActions, + val resultCode: String, + val resultText: String, + val smileJobId: String, + val partnerParams: FlutterPartnerParams, + val confidence: Double? = null, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterSmartSelfieJobResult { + val actions = FlutterActions.fromList(list[0] as List) + val resultCode = list[1] as String + val resultText = list[2] as String + val smileJobId = list[3] as String + val partnerParams = FlutterPartnerParams.fromList(list[4] as List) + val confidence = list[5] as Double? + return FlutterSmartSelfieJobResult( + actions, + resultCode, + resultText, + smileJobId, + partnerParams, + confidence, + ) + } + } + fun toList(): List = listOf( + actions.toList(), + resultCode, + resultText, + smileJobId, + partnerParams.toList(), + confidence, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterSmartSelfieJobStatusResponse( + val timestamp: String, + val jobComplete: Boolean, + val jobSuccess: Boolean, + val code: String, + val result: FlutterSmartSelfieJobResult? = null, + val resultString: String? = null, + val history: List? = null, + val imageLinks: FlutterImageLinks? = null, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterSmartSelfieJobStatusResponse { + val timestamp = list[0] as String + val jobComplete = list[1] as Boolean + val jobSuccess = list[2] as Boolean + val code = list[3] as String + val result: FlutterSmartSelfieJobResult? = (list[4] as List?)?.let { + FlutterSmartSelfieJobResult.fromList(it) + } + val resultString = list[5] as String? + val history = list[6] as List? + val imageLinks: FlutterImageLinks? = (list[7] as List?)?.let { + FlutterImageLinks.fromList(it) + } + return FlutterSmartSelfieJobStatusResponse( + timestamp, + jobComplete, + jobSuccess, + code, + result, + resultString, + history, + imageLinks, + ) + } + } + fun toList(): List = listOf( + timestamp, + jobComplete, + jobSuccess, + code, + result?.toList(), + resultString, + history, + imageLinks?.toList(), + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterSmartSelfieResponse( + val code: String, + val createdAt: String, + val jobId: String, + val jobType: FlutterJobTypeV2, + val message: String, + val partnerId: String, + val partnerParams: Map? = null, + val status: FlutterSmartSelfieStatus, + val updatedAt: String, + val userId: String, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterSmartSelfieResponse { + val code = list[0] as String + val createdAt = list[1] as String + val jobId = list[2] as String + val jobType = FlutterJobTypeV2.ofRaw(list[3] as Int)!! + val message = list[4] as String + val partnerId = list[5] as String + val partnerParams = list[6] as Map? + val status = FlutterSmartSelfieStatus.ofRaw(list[7] as Int)!! + val updatedAt = list[8] as String + val userId = list[9] as String + return FlutterSmartSelfieResponse(code, createdAt, jobId, jobType, message, partnerId, partnerParams, status, updatedAt, userId) + } + } + fun toList(): List = listOf( + code, + createdAt, + jobId, + jobType.raw, + message, + partnerId, + partnerParams, + status.raw, + updatedAt, + userId, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterDocumentVerificationJobResult( + val actions: FlutterActions, + val resultCode: String, + val resultText: String, + val smileJobId: String, + val partnerParams: FlutterPartnerParams, + val country: String? = null, + val idType: String? = null, + val idNumber: String? = null, + val fullName: String? = null, + val dob: String? = null, + val gender: String? = null, + val expirationDate: String? = null, + val documentImageBase64: String? = null, + val phoneNumber: String? = null, + val phoneNumber2: String? = null, + val address: String? = null, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterDocumentVerificationJobResult { + val actions = FlutterActions.fromList(list[0] as List) + val resultCode = list[1] as String + val resultText = list[2] as String + val smileJobId = list[3] as String + val partnerParams = FlutterPartnerParams.fromList(list[4] as List) + val country = list[5] as String? + val idType = list[6] as String? + val idNumber = list[7] as String? + val fullName = list[8] as String? + val dob = list[9] as String? + val gender = list[10] as String? + val expirationDate = list[11] as String? + val documentImageBase64 = list[12] as String? + val phoneNumber = list[13] as String? + val phoneNumber2 = list[14] as String? + val address = list[15] as String? + return FlutterDocumentVerificationJobResult(actions, resultCode, resultText, smileJobId, partnerParams, country, idType, idNumber, fullName, dob, gender, expirationDate, documentImageBase64, phoneNumber, phoneNumber2, address) + } + } + fun toList(): List = listOf( + actions.toList(), + resultCode, + resultText, + smileJobId, + partnerParams.toList(), + country, + idType, + idNumber, + fullName, + dob, + gender, + expirationDate, + documentImageBase64, + phoneNumber, + phoneNumber2, + address, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterDocumentVerificationJobStatusResponse( + val timestamp: String, + val jobComplete: Boolean, + val jobSuccess: Boolean, + val code: String, + val result: FlutterDocumentVerificationJobResult? = null, + val resultString: String? = null, + val history: List? = null, + val imageLinks: FlutterImageLinks? = null, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterDocumentVerificationJobStatusResponse { + val timestamp = list[0] as String + val jobComplete = list[1] as Boolean + val jobSuccess = list[2] as Boolean + val code = list[3] as String + val result: FlutterDocumentVerificationJobResult? = (list[4] as List?)?.let { + FlutterDocumentVerificationJobResult.fromList(it) + } + val resultString = list[5] as String? + val history = list[6] as List? + val imageLinks: FlutterImageLinks? = (list[7] as List?)?.let { + FlutterImageLinks.fromList(it) + } + return FlutterDocumentVerificationJobStatusResponse( + timestamp, + jobComplete, + jobSuccess, + code, + result, + resultString, + history, + imageLinks, + ) + } + } + fun toList(): List = listOf( + timestamp, + jobComplete, + jobSuccess, + code, + result?.toList(), + resultString, + history, + imageLinks?.toList(), + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterBiometricKycJobResult( + val actions: FlutterActions, + val resultCode: String, + val resultText: String, + val resultType: String, + val smileJobId: String, + val partnerParams: FlutterPartnerParams, + val antifraud: FlutterAntifraud? = null, + val dob: String? = null, + val photoBase64: String? = null, + val gender: String? = null, + val idType: String? = null, + val address: String? = null, + val country: String? = null, + val documentImageBase64: String? = null, + val fullData: Map? = null, + val fullName: String? = null, + val idNumber: String? = null, + val phoneNumber: String? = null, + val phoneNumber2: String? = null, + val expirationDate: String? = null, + val secondaryIdNumber: String? = null, + val idNumberPreviouslyRegistered: Boolean? = null, + val previousRegistrantsUserIds: List? = null, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterBiometricKycJobResult { + val actions = FlutterActions.fromList(list[0] as List) + val resultCode = list[1] as String + val resultText = list[2] as String + val resultType = list[3] as String + val smileJobId = list[4] as String + val partnerParams = FlutterPartnerParams.fromList(list[5] as List) + val antifraud: FlutterAntifraud? = (list[6] as List?)?.let { + FlutterAntifraud.fromList(it) + } + val dob = list[7] as String? + val photoBase64 = list[8] as String? + val gender = list[9] as String? + val idType = list[10] as String? + val address = list[11] as String? + val country = list[12] as String? + val documentImageBase64 = list[13] as String? + val fullData = list[14] as Map? + val fullName = list[15] as String? + val idNumber = list[16] as String? + val phoneNumber = list[17] as String? + val phoneNumber2 = list[18] as String? + val expirationDate = list[19] as String? + val secondaryIdNumber = list[20] as String? + val idNumberPreviouslyRegistered = list[21] as Boolean? + val previousRegistrantsUserIds = list[22] as List? + return FlutterBiometricKycJobResult(actions, resultCode, resultText, resultType, smileJobId, partnerParams, antifraud, dob, photoBase64, gender, idType, address, country, documentImageBase64, fullData, fullName, idNumber, phoneNumber, phoneNumber2, expirationDate, secondaryIdNumber, idNumberPreviouslyRegistered, previousRegistrantsUserIds) + } + } + fun toList(): List = listOf( + actions.toList(), + resultCode, + resultText, + resultType, + smileJobId, + partnerParams.toList(), + antifraud?.toList(), + dob, + photoBase64, + gender, + idType, + address, + country, + documentImageBase64, + fullData, + fullName, + idNumber, + phoneNumber, + phoneNumber2, + expirationDate, + secondaryIdNumber, + idNumberPreviouslyRegistered, + previousRegistrantsUserIds, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterBiometricKycJobStatusResponse( + val timestamp: String, + val jobComplete: Boolean, + val jobSuccess: Boolean, + val code: String, + val result: FlutterBiometricKycJobResult? = null, + val resultString: String? = null, + val history: List? = null, + val imageLinks: FlutterImageLinks? = null, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterBiometricKycJobStatusResponse { + val timestamp = list[0] as String + val jobComplete = list[1] as Boolean + val jobSuccess = list[2] as Boolean + val code = list[3] as String + val result: FlutterBiometricKycJobResult? = (list[4] as List?)?.let { + FlutterBiometricKycJobResult.fromList(it) + } + val resultString = list[5] as String? + val history = list[6] as List? + val imageLinks: FlutterImageLinks? = (list[7] as List?)?.let { + FlutterImageLinks.fromList(it) + } + return FlutterBiometricKycJobStatusResponse( + timestamp, + jobComplete, + jobSuccess, + code, + result, + resultString, + history, + imageLinks, + ) + } + } + fun toList(): List = listOf( + timestamp, + jobComplete, + jobSuccess, + code, + result?.toList(), + resultString, + history, + imageLinks?.toList(), + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterEnhancedDocumentVerificationJobResult( + val actions: FlutterActions, + val resultCode: String, + val resultText: String, + val resultType: String, + val smileJobId: String, + val partnerParams: FlutterPartnerParams, + val antifraud: FlutterAntifraud? = null, + val dob: String? = null, + val photoBase64: String? = null, + val gender: String? = null, + val idType: String? = null, + val address: String? = null, + val country: String? = null, + val documentImageBase64: String? = null, + val fullData: Map? = null, + val fullName: String? = null, + val idNumber: String? = null, + val phoneNumber: String? = null, + val phoneNumber2: String? = null, + val expirationDate: String? = null, + val secondaryIdNumber: String? = null, + val idNumberPreviouslyRegistered: Boolean? = null, + val previousRegistrantsUserIds: List? = null, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterEnhancedDocumentVerificationJobResult { + val actions = FlutterActions.fromList(list[0] as List) + val resultCode = list[1] as String + val resultText = list[2] as String + val resultType = list[3] as String + val smileJobId = list[4] as String + val partnerParams = FlutterPartnerParams.fromList(list[5] as List) + val antifraud: FlutterAntifraud? = (list[6] as List?)?.let { + FlutterAntifraud.fromList(it) + } + val dob = list[7] as String? + val photoBase64 = list[8] as String? + val gender = list[9] as String? + val idType = list[10] as String? + val address = list[11] as String? + val country = list[12] as String? + val documentImageBase64 = list[13] as String? + val fullData = list[14] as Map? + val fullName = list[15] as String? + val idNumber = list[16] as String? + val phoneNumber = list[17] as String? + val phoneNumber2 = list[18] as String? + val expirationDate = list[19] as String? + val secondaryIdNumber = list[20] as String? + val idNumberPreviouslyRegistered = list[21] as Boolean? + val previousRegistrantsUserIds = list[22] as List? + return FlutterEnhancedDocumentVerificationJobResult(actions, resultCode, resultText, resultType, smileJobId, partnerParams, antifraud, dob, photoBase64, gender, idType, address, country, documentImageBase64, fullData, fullName, idNumber, phoneNumber, phoneNumber2, expirationDate, secondaryIdNumber, idNumberPreviouslyRegistered, previousRegistrantsUserIds) + } + } + fun toList(): List = listOf( + actions.toList(), + resultCode, + resultText, + resultType, + smileJobId, + partnerParams.toList(), + antifraud?.toList(), + dob, + photoBase64, + gender, + idType, + address, + country, + documentImageBase64, + fullData, + fullName, + idNumber, + phoneNumber, + phoneNumber2, + expirationDate, + secondaryIdNumber, + idNumberPreviouslyRegistered, + previousRegistrantsUserIds, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterEnhancedDocumentVerificationJobStatusResponse( + val timestamp: String, + val jobComplete: Boolean, + val jobSuccess: Boolean, + val code: String, + val result: FlutterEnhancedDocumentVerificationJobResult? = null, + val resultString: String? = null, + val history: List? = null, + val imageLinks: FlutterImageLinks? = null, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterEnhancedDocumentVerificationJobStatusResponse { + val timestamp = list[0] as String + val jobComplete = list[1] as Boolean + val jobSuccess = list[2] as Boolean + val code = list[3] as String + val result: FlutterEnhancedDocumentVerificationJobResult? = (list[4] as List?)?.let { + FlutterEnhancedDocumentVerificationJobResult.fromList(it) + } + val resultString = list[5] as String? + val history = list[6] as List? + val imageLinks: FlutterImageLinks? = (list[7] as List?)?.let { + FlutterImageLinks.fromList(it) + } + return FlutterEnhancedDocumentVerificationJobStatusResponse( + timestamp, + jobComplete, + jobSuccess, + code, + result, + resultString, + history, + imageLinks, + ) + } + } + fun toList(): List = listOf( + timestamp, + jobComplete, + jobSuccess, + code, + result?.toList(), + resultString, + history, + imageLinks?.toList(), + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterProductsConfigRequest( + val partnerId: String, + val timestamp: String, + val signature: String, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterProductsConfigRequest { + val partnerId = list[0] as String + val timestamp = list[1] as String + val signature = list[2] as String + return FlutterProductsConfigRequest(partnerId, timestamp, signature) + } + } + fun toList(): List = listOf( + partnerId, + timestamp, + signature, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterProductsConfigResponse( + val consentRequired: Map?>, + val idSelection: FlutterIdSelection, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterProductsConfigResponse { + val consentRequired = list[0] as Map?> + val idSelection = FlutterIdSelection.fromList(list[1] as List) + return FlutterProductsConfigResponse(consentRequired, idSelection) + } + } + fun toList(): List = listOf( + consentRequired, + idSelection.toList(), + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterIdSelection( + val basicKyc: Map?>, + val biometricKyc: Map?>, + val enhancedKyc: Map?>, + val documentVerification: Map?>, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterIdSelection { + val basicKyc = list[0] as Map?> + val biometricKyc = list[1] as Map?> + val enhancedKyc = list[2] as Map?> + val documentVerification = list[3] as Map?> + return FlutterIdSelection(basicKyc, biometricKyc, enhancedKyc, documentVerification) + } + } + fun toList(): List = listOf( + basicKyc, + biometricKyc, + enhancedKyc, + documentVerification, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterValidDocumentsResponse(val validDocuments: List) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterValidDocumentsResponse { + val validDocuments = list[0] as List + return FlutterValidDocumentsResponse(validDocuments) + } + } + fun toList(): List = listOf( + validDocuments, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterValidDocument(val country: FlutterCountry, val idTypes: List) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterValidDocument { + val country = FlutterCountry.fromList(list[0] as List) + val idTypes = list[1] as List + return FlutterValidDocument(country, idTypes) + } + } + fun toList(): List = listOf( + country.toList(), + idTypes, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterCountry(val code: String, val continent: String, val name: String) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterCountry { + val code = list[0] as String + val continent = list[1] as String + val name = list[2] as String + return FlutterCountry(code, continent, name) + } + } + fun toList(): List = listOf( + code, + continent, + name, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterIdType( + val code: String, + val example: List, + val hasBack: Boolean, + val name: String, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterIdType { + val code = list[0] as String + val example = list[1] as List + val hasBack = list[2] as Boolean + val name = list[3] as String + return FlutterIdType(code, example, hasBack, name) + } + } + fun toList(): List = listOf( + code, + example, + hasBack, + name, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterServicesResponse( + val bankCodes: List, + val hostedWeb: FlutterHostedWeb, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterServicesResponse { + val bankCodes = list[0] as List + val hostedWeb = FlutterHostedWeb.fromList(list[1] as List) + return FlutterServicesResponse(bankCodes, hostedWeb) + } + } + fun toList(): List = listOf( + bankCodes, + hostedWeb.toList(), + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterBankCode(val name: String, val code: String) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterBankCode { + val name = list[0] as String + val code = list[1] as String + return FlutterBankCode(name, code) + } + } + fun toList(): List = listOf( + name, + code, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterHostedWeb( + val basicKyc: Map, + val biometricKyc: Map, + val enhancedKyc: Map, + val documentVerification: Map, + val enhancedKycSmartSelfie: Map, + val enhancedDocumentVerification: Map, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterHostedWeb { + val basicKyc = list[0] as Map + val biometricKyc = list[1] as Map + val enhancedKyc = list[2] as Map + val documentVerification = list[3] as Map + val enhancedKycSmartSelfie = list[4] as Map + val enhancedDocumentVerification = list[5] as Map + return FlutterHostedWeb( + basicKyc, + biometricKyc, + enhancedKyc, + documentVerification, + enhancedKycSmartSelfie, + enhancedDocumentVerification, + ) + } + } + fun toList(): List = listOf( + basicKyc, + biometricKyc, + enhancedKyc, + documentVerification, + enhancedKycSmartSelfie, + enhancedDocumentVerification, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterCountryInfo( + val countryCode: String, + val name: String, + val availableIdTypes: List, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterCountryInfo { + val countryCode = list[0] as String + val name = list[1] as String + val availableIdTypes = list[2] as List + return FlutterCountryInfo(countryCode, name, availableIdTypes) + } + } + fun toList(): List = listOf( + countryCode, + name, + availableIdTypes, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterAvailableIdType( + val idTypeKey: String, + val label: String, + val requiredFields: List, + val testData: String? = null, + val idNumberRegex: String? = null, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterAvailableIdType { + val idTypeKey = list[0] as String + val label = list[1] as String + val requiredFields = list[2] as List + val testData = list[3] as String? + val idNumberRegex = list[4] as String? + return FlutterAvailableIdType(idTypeKey, label, requiredFields, testData, idNumberRegex) + } + } + fun toList(): List = listOf( + idTypeKey, + label, + requiredFields, + testData, + idNumberRegex, + ) +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class FlutterConfig( + val partnerId: String, + val authToken: String, + val prodBaseUrl: String, + val sandboxBaseUrl: String, + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): FlutterConfig { + val partnerId = list[0] as String + val authToken = list[1] as String + val prodBaseUrl = list[2] as String + val sandboxBaseUrl = list[3] as String + return FlutterConfig(partnerId, authToken, prodBaseUrl, sandboxBaseUrl) + } + } + fun toList(): List = listOf( + partnerId, + authToken, + prodBaseUrl, + sandboxBaseUrl, + ) +} + +@Suppress("UNCHECKED_CAST") +private object SmileIDApiCodec : StandardMessageCodec() { + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { + return when (type) { + 128.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterActions.fromList(it) + } + } + 129.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterAntifraud.fromList(it) + } + } + 130.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterAuthenticationRequest.fromList(it) + } + } + 131.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterAuthenticationResponse.fromList(it) + } + } + 132.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterAvailableIdType.fromList(it) + } + } + 133.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterBankCode.fromList(it) + } + } + 134.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterBiometricKycJobResult.fromList(it) + } + } + 135.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterBiometricKycJobResult.fromList(it) + } + } + 136.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterBiometricKycJobStatusResponse.fromList(it) + } + } + 137.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterConfig.fromList(it) + } + } + 138.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterConsentInfo.fromList(it) + } + } + 139.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterConsentInformation.fromList(it) + } + } + 140.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterCountry.fromList(it) + } + } + 141.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterCountryInfo.fromList(it) + } + } + 142.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterDocumentVerificationJobResult.fromList(it) + } + } + 143.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterDocumentVerificationJobResult.fromList(it) + } + } + 144.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterDocumentVerificationJobStatusResponse.fromList(it) + } + } + 145.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterEnhancedDocumentVerificationJobResult.fromList(it) + } + } + 146.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterEnhancedDocumentVerificationJobResult.fromList(it) + } + } + 147.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterEnhancedDocumentVerificationJobStatusResponse.fromList(it) + } + } + 148.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterEnhancedKycAsyncResponse.fromList(it) + } + } + 149.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterEnhancedKycRequest.fromList(it) + } + } + 150.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterEnhancedKycResponse.fromList(it) + } + } + 151.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterHostedWeb.fromList(it) + } + } + 152.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterIdInfo.fromList(it) + } + } + 153.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterIdSelection.fromList(it) + } + } + 154.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterIdType.fromList(it) + } + } + 155.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterImageLinks.fromList(it) + } + } + 156.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterJobStatusRequest.fromList(it) + } + } + 157.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterPartnerParams.fromList(it) + } + } + 158.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterPrepUploadRequest.fromList(it) + } + } + 159.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterPrepUploadResponse.fromList(it) + } + } + 160.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterProductsConfigRequest.fromList(it) + } + } + 161.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterProductsConfigResponse.fromList(it) + } + } + 162.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterServicesResponse.fromList(it) + } + } + 163.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterSmartSelfieJobResult.fromList(it) + } + } + 164.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterSmartSelfieJobResult.fromList(it) + } + } + 165.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterSmartSelfieJobStatusResponse.fromList(it) + } + } + 166.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterSmartSelfieResponse.fromList(it) + } + } + 167.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterSuspectUser.fromList(it) + } + } + 168.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterUploadImageInfo.fromList(it) + } + } + 169.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterUploadRequest.fromList(it) + } + } + 170.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterValidDocument.fromList(it) + } + } + 171.toByte() -> { + return (readValue(buffer) as? List)?.let { + FlutterValidDocumentsResponse.fromList(it) + } + } + else -> super.readValueOfType(type, buffer) + } + } + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { + when (value) { + is FlutterActions -> { + stream.write(128) + writeValue(stream, value.toList()) + } + is FlutterAntifraud -> { + stream.write(129) + writeValue(stream, value.toList()) + } + is FlutterAuthenticationRequest -> { + stream.write(130) + writeValue(stream, value.toList()) + } + is FlutterAuthenticationResponse -> { + stream.write(131) + writeValue(stream, value.toList()) + } + is FlutterAvailableIdType -> { + stream.write(132) + writeValue(stream, value.toList()) + } + is FlutterBankCode -> { + stream.write(133) + writeValue(stream, value.toList()) + } + is FlutterBiometricKycJobResult -> { + stream.write(134) + writeValue(stream, value.toList()) + } + is FlutterBiometricKycJobResult -> { + stream.write(135) + writeValue(stream, value.toList()) + } + is FlutterBiometricKycJobStatusResponse -> { + stream.write(136) + writeValue(stream, value.toList()) + } + is FlutterConfig -> { + stream.write(137) + writeValue(stream, value.toList()) + } + is FlutterConsentInfo -> { + stream.write(138) + writeValue(stream, value.toList()) + } + is FlutterConsentInformation -> { + stream.write(139) + writeValue(stream, value.toList()) + } + is FlutterCountry -> { + stream.write(140) + writeValue(stream, value.toList()) + } + is FlutterCountryInfo -> { + stream.write(141) + writeValue(stream, value.toList()) + } + is FlutterDocumentVerificationJobResult -> { + stream.write(142) + writeValue(stream, value.toList()) + } + is FlutterDocumentVerificationJobResult -> { + stream.write(143) + writeValue(stream, value.toList()) + } + is FlutterDocumentVerificationJobStatusResponse -> { + stream.write(144) + writeValue(stream, value.toList()) + } + is FlutterEnhancedDocumentVerificationJobResult -> { + stream.write(145) + writeValue(stream, value.toList()) + } + is FlutterEnhancedDocumentVerificationJobResult -> { + stream.write(146) + writeValue(stream, value.toList()) + } + is FlutterEnhancedDocumentVerificationJobStatusResponse -> { + stream.write(147) + writeValue(stream, value.toList()) + } + is FlutterEnhancedKycAsyncResponse -> { + stream.write(148) + writeValue(stream, value.toList()) + } + is FlutterEnhancedKycRequest -> { + stream.write(149) + writeValue(stream, value.toList()) + } + is FlutterEnhancedKycResponse -> { + stream.write(150) + writeValue(stream, value.toList()) + } + is FlutterHostedWeb -> { + stream.write(151) + writeValue(stream, value.toList()) + } + is FlutterIdInfo -> { + stream.write(152) + writeValue(stream, value.toList()) + } + is FlutterIdSelection -> { + stream.write(153) + writeValue(stream, value.toList()) + } + is FlutterIdType -> { + stream.write(154) + writeValue(stream, value.toList()) + } + is FlutterImageLinks -> { + stream.write(155) + writeValue(stream, value.toList()) + } + is FlutterJobStatusRequest -> { + stream.write(156) + writeValue(stream, value.toList()) + } + is FlutterPartnerParams -> { + stream.write(157) + writeValue(stream, value.toList()) + } + is FlutterPrepUploadRequest -> { + stream.write(158) + writeValue(stream, value.toList()) + } + is FlutterPrepUploadResponse -> { + stream.write(159) + writeValue(stream, value.toList()) + } + is FlutterProductsConfigRequest -> { + stream.write(160) + writeValue(stream, value.toList()) + } + is FlutterProductsConfigResponse -> { + stream.write(161) + writeValue(stream, value.toList()) + } + is FlutterServicesResponse -> { + stream.write(162) + writeValue(stream, value.toList()) + } + is FlutterSmartSelfieJobResult -> { + stream.write(163) + writeValue(stream, value.toList()) + } + is FlutterSmartSelfieJobResult -> { + stream.write(164) + writeValue(stream, value.toList()) + } + is FlutterSmartSelfieJobStatusResponse -> { + stream.write(165) + writeValue(stream, value.toList()) + } + is FlutterSmartSelfieResponse -> { + stream.write(166) + writeValue(stream, value.toList()) + } + is FlutterSuspectUser -> { + stream.write(167) + writeValue(stream, value.toList()) + } + is FlutterUploadImageInfo -> { + stream.write(168) + writeValue(stream, value.toList()) + } + is FlutterUploadRequest -> { + stream.write(169) + writeValue(stream, value.toList()) + } + is FlutterValidDocument -> { + stream.write(170) + writeValue(stream, value.toList()) + } + is FlutterValidDocumentsResponse -> { + stream.write(171) + writeValue(stream, value.toList()) + } + else -> super.writeValue(stream, value) + } + } +} + +/** Generated interface from Pigeon that represents a handler of messages from Flutter. */ +interface SmileIDApi { + fun initializeWithApiKey( + apiKey: String, + config: FlutterConfig, + useSandbox: Boolean, + enableCrashReporting: Boolean, + ) + fun initializeWithConfig( + config: FlutterConfig, + useSandbox: Boolean, + enableCrashReporting: Boolean, + ) + fun initialize(useSandbox: Boolean) + fun setCallbackUrl(callbackUrl: String) + fun setAllowOfflineMode(allowOfflineMode: Boolean) + fun getSubmittedJobs(): List + fun getUnsubmittedJobs(): List + fun cleanup(jobId: String) + fun cleanupJobs(jobIds: List) + fun submitJob(jobId: String, deleteFilesOnSuccess: Boolean) + fun authenticate( + request: FlutterAuthenticationRequest, + callback: (Result) -> Unit, + ) + fun prepUpload( + request: FlutterPrepUploadRequest, + callback: (Result) -> Unit, + ) + fun upload(url: String, request: FlutterUploadRequest, callback: (Result) -> Unit) + fun doEnhancedKyc( + request: FlutterEnhancedKycRequest, + callback: (Result) -> Unit, + ) + fun doEnhancedKycAsync( + request: FlutterEnhancedKycRequest, + callback: (Result) -> Unit, + ) + fun getSmartSelfieJobStatus( + request: FlutterJobStatusRequest, + callback: (Result) -> Unit, + ) + fun doSmartSelfieEnrollment( + signature: String, + timestamp: String, + selfieImage: String, + livenessImages: List, + userId: String, + partnerParams: Map?, + callbackUrl: String?, + sandboxResult: Long?, + allowNewEnroll: Boolean?, + callback: (Result) -> Unit, + ) + fun doSmartSelfieAuthentication( + signature: String, + timestamp: String, + selfieImage: String, + livenessImages: List, + userId: String, + partnerParams: Map?, + callbackUrl: String?, + sandboxResult: Long?, + callback: (Result) -> Unit, + ) + fun getDocumentVerificationJobStatus( + request: FlutterJobStatusRequest, + callback: (Result) -> Unit, + ) + fun getBiometricKycJobStatus( + request: FlutterJobStatusRequest, + callback: (Result) -> Unit, + ) + fun getEnhancedDocumentVerificationJobStatus( + request: FlutterJobStatusRequest, + callback: (Result) -> Unit, + ) + fun getProductsConfig( + request: FlutterProductsConfigRequest, + callback: (Result) -> Unit, + ) + fun getValidDocuments( + request: FlutterProductsConfigRequest, + callback: (Result) -> Unit, + ) + fun getServices(callback: (Result) -> Unit) + fun pollSmartSelfieJobStatus( + request: FlutterJobStatusRequest, + interval: Long, + numAttempts: Long, + callback: (Result) -> Unit, + ) + fun pollDocumentVerificationJobStatus( + request: FlutterJobStatusRequest, + interval: Long, + numAttempts: Long, + callback: (Result) -> Unit, + ) + fun pollBiometricKycJobStatus( + request: FlutterJobStatusRequest, + interval: Long, + numAttempts: Long, + callback: (Result) -> Unit, + ) + fun pollEnhancedDocumentVerificationJobStatus( + request: FlutterJobStatusRequest, + interval: Long, + numAttempts: Long, + callback: (Result) -> Unit, + ) + + companion object { + /** The codec used by SmileIDApi. */ + val codec: MessageCodec by lazy { + SmileIDApiCodec + } + + /** Sets up an instance of `SmileIDApi` to handle messages through the `binaryMessenger`. */ + @Suppress("UNCHECKED_CAST") + fun setUp(binaryMessenger: BinaryMessenger, api: SmileIDApi?) { + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.initializeWithApiKey", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val apiKeyArg = args[0] as String + val configArg = args[1] as FlutterConfig + val useSandboxArg = args[2] as Boolean + val enableCrashReportingArg = args[3] as Boolean + var wrapped: List + try { + api.initializeWithApiKey( + apiKeyArg, + configArg, + useSandboxArg, + enableCrashReportingArg, + ) + wrapped = listOf(null) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.initializeWithConfig", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val configArg = args[0] as FlutterConfig + val useSandboxArg = args[1] as Boolean + val enableCrashReportingArg = args[2] as Boolean + var wrapped: List + try { + api.initializeWithConfig( + configArg, + useSandboxArg, + enableCrashReportingArg, + ) + wrapped = listOf(null) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.initialize", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val useSandboxArg = args[0] as Boolean + var wrapped: List + try { + api.initialize(useSandboxArg) + wrapped = listOf(null) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.setCallbackUrl", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val callbackUrlArg = args[0] as String + var wrapped: List + try { + api.setCallbackUrl(callbackUrlArg) + wrapped = listOf(null) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.setAllowOfflineMode", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val allowOfflineModeArg = args[0] as Boolean + var wrapped: List + try { + api.setAllowOfflineMode(allowOfflineModeArg) + wrapped = listOf(null) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.getSubmittedJobs", + codec, + ) + if (api != null) { + channel.setMessageHandler { _, reply -> + var wrapped: List + try { + wrapped = listOf(api.getSubmittedJobs()) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.getUnsubmittedJobs", + codec, + ) + if (api != null) { + channel.setMessageHandler { _, reply -> + var wrapped: List + try { + wrapped = listOf(api.getUnsubmittedJobs()) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.cleanup", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val jobIdArg = args[0] as String + var wrapped: List + try { + api.cleanup(jobIdArg) + wrapped = listOf(null) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.cleanupJobs", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val jobIdsArg = args[0] as List + var wrapped: List + try { + api.cleanupJobs(jobIdsArg) + wrapped = listOf(null) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.submitJob", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val jobIdArg = args[0] as String + val deleteFilesOnSuccessArg = args[1] as Boolean + var wrapped: List + try { + api.submitJob(jobIdArg, deleteFilesOnSuccessArg) + wrapped = listOf(null) + } catch (exception: Throwable) { + wrapped = wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.authenticate", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterAuthenticationRequest + api.authenticate( + requestArg, + ) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.prepUpload", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterPrepUploadRequest + api.prepUpload(requestArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.upload", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val urlArg = args[0] as String + val requestArg = args[1] as FlutterUploadRequest + api.upload(urlArg, requestArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.doEnhancedKyc", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterEnhancedKycRequest + api.doEnhancedKyc( + requestArg, + ) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.doEnhancedKycAsync", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterEnhancedKycRequest + api.doEnhancedKycAsync( + requestArg, + ) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.getSmartSelfieJobStatus", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterJobStatusRequest + api.getSmartSelfieJobStatus( + requestArg, + ) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.doSmartSelfieEnrollment", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val signatureArg = args[0] as String + val timestampArg = args[1] as String + val selfieImageArg = args[2] as String + val livenessImagesArg = args[3] as List + val userIdArg = args[4] as String + val partnerParamsArg = args[5] as Map? + val callbackUrlArg = args[6] as String? + val sandboxResultArg = args[7].let { + if (it is Int) it.toLong() else it as Long? + } + val allowNewEnrollArg = args[8] as Boolean? + api.doSmartSelfieEnrollment(signatureArg, timestampArg, selfieImageArg, livenessImagesArg, userIdArg, partnerParamsArg, callbackUrlArg, sandboxResultArg, allowNewEnrollArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.doSmartSelfieAuthentication", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val signatureArg = args[0] as String + val timestampArg = args[1] as String + val selfieImageArg = args[2] as String + val livenessImagesArg = args[3] as List + val userIdArg = args[4] as String + val partnerParamsArg = args[5] as Map? + val callbackUrlArg = args[6] as String? + val sandboxResultArg = args[7].let { + if (it is Int) it.toLong() else it as Long? + } + api.doSmartSelfieAuthentication( + signatureArg, + timestampArg, + selfieImageArg, + livenessImagesArg, + userIdArg, + partnerParamsArg, + callbackUrlArg, + sandboxResultArg, + ) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.getDocumentVerificationJobStatus", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterJobStatusRequest + api.getDocumentVerificationJobStatus( + requestArg, + ) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.getBiometricKycJobStatus", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterJobStatusRequest + api.getBiometricKycJobStatus( + requestArg, + ) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.getEnhancedDocumentVerificationJobStatus", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterJobStatusRequest + api.getEnhancedDocumentVerificationJobStatus(requestArg) { + result: + Result, + -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.getProductsConfig", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterProductsConfigRequest + api.getProductsConfig( + requestArg, + ) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.getValidDocuments", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterProductsConfigRequest + api.getValidDocuments( + requestArg, + ) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.getServices", + codec, + ) + if (api != null) { + channel.setMessageHandler { _, reply -> + api.getServices { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.pollSmartSelfieJobStatus", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterJobStatusRequest + val intervalArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val numAttemptsArg = args[2].let { + if (it is Int) it.toLong() else it as Long + } + api.pollSmartSelfieJobStatus( + requestArg, + intervalArg, + numAttemptsArg, + ) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.pollDocumentVerificationJobStatus", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterJobStatusRequest + val intervalArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val numAttemptsArg = args[2].let { + if (it is Int) it.toLong() else it as Long + } + api.pollDocumentVerificationJobStatus( + requestArg, + intervalArg, + numAttemptsArg, + ) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.pollBiometricKycJobStatus", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterJobStatusRequest + val intervalArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val numAttemptsArg = args[2].let { + if (it is Int) it.toLong() else it as Long + } + api.pollBiometricKycJobStatus( + requestArg, + intervalArg, + numAttemptsArg, + ) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = + BasicMessageChannel( + binaryMessenger, + "dev.flutter.pigeon.smileid.SmileIDApi.pollEnhancedDocumentVerificationJobStatus", + codec, + ) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val requestArg = args[0] as FlutterJobStatusRequest + val intervalArg = args[1].let { if (it is Int) it.toLong() else it as Long } + val numAttemptsArg = args[2].let { + if (it is Int) it.toLong() else it as Long + } + api.pollEnhancedDocumentVerificationJobStatus( + requestArg, + intervalArg, + numAttemptsArg, + ) { + result: + Result, + -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + } + } +} diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/results/DocumentCaptureResult.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/results/DocumentCaptureResult.kt new file mode 100644 index 0000000..827befa --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/results/DocumentCaptureResult.kt @@ -0,0 +1,12 @@ +package com.smileidentity.flutter.results + +import java.io.File + +data class DocumentCaptureResult( + val selfieFile: File? = null, + val documentFrontFile: File? = null, + val livenessFiles: List? = null, + val documentBackFile: File? = null, + val didSubmitDocumentVerificationJob: Boolean? = null, + val didSubmitEnhancedDocVJob: Boolean? = null, +) diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/results/SmartSelfieCaptureResult.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/results/SmartSelfieCaptureResult.kt new file mode 100644 index 0000000..5f0a3c6 --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/results/SmartSelfieCaptureResult.kt @@ -0,0 +1,10 @@ +package com.smileidentity.flutter.results +import com.smileidentity.models.v2.SmartSelfieResponse +import java.io.File + +data class SmartSelfieCaptureResult( + val selfieFile: File? = null, + val livenessFiles: List? = null, + val apiResponse: SmartSelfieResponse? = null, + val didSubmitBiometricKycJob: Boolean? = null, +) diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/utils/DocumentCaptureResultAdapter.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/utils/DocumentCaptureResultAdapter.kt new file mode 100644 index 0000000..194244d --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/utils/DocumentCaptureResultAdapter.kt @@ -0,0 +1,102 @@ +package com.smileidentity.flutter.utils + +import com.smileidentity.flutter.results.DocumentCaptureResult +import com.squareup.moshi.FromJson +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter +import com.squareup.moshi.Moshi +import com.squareup.moshi.ToJson +import java.io.File +import java.lang.reflect.Type + +class DocumentCaptureResultAdapter : JsonAdapter() { + @FromJson + override fun fromJson(reader: JsonReader): DocumentCaptureResult { + reader.beginObject() + var selfieFile: File? = null + var frontFile: File? = null + var backFile: File? = null + var livenessFiles: MutableList? = null + var didSubmitDocumentVerificationJob: Boolean? = null + var didSubmitEnhancedDocVJob: Boolean? = null + while (reader.hasNext()) { + when (reader.nextName()) { + "selfieFile" -> selfieFile = reader.nextString()?.let { File(it) } + "documentFrontFile" -> frontFile = reader.nextString()?.let { File(it) } + "documentBackFile" -> backFile = reader.nextString()?.let { File(it) } + "livenessFiles" -> { + livenessFiles = mutableListOf() + reader.beginArray() + while (reader.hasNext()) { + reader.nextString()?.let { livenessFiles.add(File(it)) } + } + reader.endArray() + } + + "didSubmitDocumentVerificationJob" -> + didSubmitDocumentVerificationJob = + reader.nextBoolean() + + "didSubmitEnhancedDocVJob" -> didSubmitEnhancedDocVJob = reader.nextBoolean() + else -> reader.skipValue() + } + } + reader.endObject() + + return DocumentCaptureResult( + selfieFile = selfieFile, + documentFrontFile = frontFile, + documentBackFile = backFile, + livenessFiles = livenessFiles, + didSubmitDocumentVerificationJob = didSubmitDocumentVerificationJob, + didSubmitEnhancedDocVJob = didSubmitEnhancedDocVJob, + ) + } + + @ToJson + override fun toJson(writer: JsonWriter, value: DocumentCaptureResult?) { + if (value == null) { + writer.nullValue() + return + } + + writer.beginObject() + writer.name("selfieFile").value(value.selfieFile?.absolutePath) + writer.name("documentFrontFile").value(value.documentFrontFile?.absolutePath) + writer.name("documentBackFile").value(value.documentBackFile?.absolutePath) + + writer.name("livenessFiles") + if (value.livenessFiles == null) { + writer.nullValue() + } else { + writer.beginArray() + for (file in value.livenessFiles) { + writer.value(file.absolutePath) + } + writer.endArray() + } + + writer + .name("didSubmitDocumentVerificationJob") + .value(value.didSubmitDocumentVerificationJob) + writer.name("didSubmitEnhancedDocVJob").value(value.didSubmitEnhancedDocVJob) + + writer.endObject() + } + + companion object { + val FACTORY = + object : Factory { + override fun create( + type: Type, + annotations: Set, + moshi: Moshi, + ): JsonAdapter<*>? = if (type == DocumentCaptureResult::class.java) { + DocumentCaptureResultAdapter() + } else { + null + } + } + } +} diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/utils/SelfieCaptureResultAdapter.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/utils/SelfieCaptureResultAdapter.kt new file mode 100644 index 0000000..922539b --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/utils/SelfieCaptureResultAdapter.kt @@ -0,0 +1,93 @@ +package com.smileidentity.flutter.utils + +import com.smileidentity.SmileID +import com.smileidentity.flutter.results.SmartSelfieCaptureResult +import com.smileidentity.models.v2.SmartSelfieResponse +import com.squareup.moshi.FromJson +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonAdapter.Factory +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter +import com.squareup.moshi.ToJson +import java.io.File + +class SelfieCaptureResultAdapter : JsonAdapter() { + @FromJson + override fun fromJson(reader: JsonReader): SmartSelfieCaptureResult { + reader.beginObject() + var selfieFile: File? = null + var livenessFiles: List? = null + var didSubmitBiometricKycJob: Boolean? = false + var apiResponse: SmartSelfieResponse? = null + + while (reader.hasNext()) { + when (reader.nextName()) { + "selfieFile" -> selfieFile = reader.nextString()?.let { File(it) } + "livenessFiles" -> { + // Assuming livenessFiles is an array of file paths in the JSON + val files = mutableListOf() + reader.beginArray() + while (reader.hasNext()) { + reader.nextString()?.let { files.add(File(it)) } + } + reader.endArray() + livenessFiles = files + } + + "apiResponse" -> + apiResponse = + SmileID.moshi.adapter(SmartSelfieResponse::class.java).fromJson(reader) + "didSubmitBiometricKycJob" -> reader.nextBoolean() + + else -> reader.skipValue() + } + } + + reader.endObject() + return SmartSelfieCaptureResult( + selfieFile = selfieFile, + livenessFiles = livenessFiles, + apiResponse = apiResponse, + didSubmitBiometricKycJob = didSubmitBiometricKycJob, + ) + } + + @ToJson + override fun toJson(writer: JsonWriter, value: SmartSelfieCaptureResult?) { + if (value == null) { + writer.nullValue() + return + } + writer.beginObject() + writer.name("selfieFile").value(value.selfieFile?.absolutePath) + + writer.name("livenessFiles") + writer.beginArray() + value.livenessFiles?.forEach { writer.value(it.absolutePath) } + writer.endArray() + writer.name("didSubmitBiometricKycJob").value(value.didSubmitBiometricKycJob) + writer.name("apiResponse") + if (value.apiResponse != null) { + SmileID.moshi.adapter(SmartSelfieResponse::class.java).toJson( + writer, + value.apiResponse, + ) + } else { + writer.nullValue() + } + writer.endObject() + } + + companion object { + val FACTORY = + Factory { type, annotations, moshi -> + if (type == + SmartSelfieCaptureResult::class.java + ) { + SelfieCaptureResultAdapter() + } else { + null + } + } + } +} diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/utils/SmileIDUtils.kt b/android/lib/src/main/kotlin/com/smileidentity/flutter/utils/SmileIDUtils.kt new file mode 100644 index 0000000..bfd9177 --- /dev/null +++ b/android/lib/src/main/kotlin/com/smileidentity/flutter/utils/SmileIDUtils.kt @@ -0,0 +1,16 @@ +package com.smileidentity.flutter.utils +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale +import java.util.TimeZone + +/** + * Converts current time to ISO8601 string with milliseconds in UTC + * Format: yyyy-MM-dd'T'HH:mm:ss.SSS'Z' + */ +internal fun getCurrentIsoTimestamp(): String { + val pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" + val sdf = SimpleDateFormat(pattern, Locale.US) + sdf.timeZone = TimeZone.getTimeZone("UTC") + return sdf.format(Date()) +} diff --git a/android/lib/src/test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt b/android/lib/src/test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt new file mode 100644 index 0000000..ce5035a --- /dev/null +++ b/android/lib/src/test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt @@ -0,0 +1,77 @@ +package com.smileidentity.flutter + +import FlutterAuthenticationRequest +import FlutterAuthenticationResponse +import FlutterEnhancedKycAsyncResponse +import FlutterEnhancedKycRequest +import SmileIDApi +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.confirmVerified +import io.mockk.mockk +import kotlin.test.Test + +/* + * This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation. + * + * Once you have built the plugin's example app, you can run these tests from the command + * line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or + * you can run them directly from IDEs that support JUnit such as Android Studio. + */ +internal class SmileIDPluginTest { + @Test + fun `when we call authenticate and pass a request object, we get a successful callback`() { + val request = mockk() + val callback = mockk<(Result) -> Unit>() + val api = mockk() + + coEvery { + api.authenticate( + request = request, + callback = callback, + ) + } returns Unit + + api.authenticate( + request = request, + callback = callback, + ) + + coVerify { + api.authenticate( + request = request, + callback = callback, + ) + } + + confirmVerified(api) + } + + @Test + fun `when we call doEnhancedKycAsync with a request object, we get a successful callback`() { + val request = mockk() + val callback = mockk<(Result) -> Unit>() + val api = mockk() + + coEvery { + api.doEnhancedKycAsync( + request = request, + callback = callback, + ) + } returns Unit + + api.doEnhancedKycAsync( + request = request, + callback = callback, + ) + + coVerify { + api.doEnhancedKycAsync( + request = request, + callback = callback, + ) + } + + confirmVerified(api) + } +} From 16e8d4ff872829a765a2391bf4f94264530146de Mon Sep 17 00:00:00 2001 From: Harun Wangereka Date: Mon, 9 Jun 2025 14:48:10 +0300 Subject: [PATCH 07/18] Created a lib folder and moved android lib logic to the folder --- android/gradle/libs.versions.toml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index 94ba266..ed85be1 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -3,11 +3,10 @@ android-gradle-plugin = "8.7.3" flutter-plugin-loader = "1.0.0" kotlin = "2.1.0" kotlin-immutable-collections = "0.4.0" -ktlint-plugin = "12.1.3" +ktlint-plugin = "12.1.2" mockk = "1.13.13" mlkit = "17.0.2" -smile-id = "11.0.1" -smile-id-snapshot = "11.0.1-SNAPSHOT" +smile-id = "11.0.3-20250609.065709-4" [libraries] androidx-core-ktx = { module = "androidx.core:core-ktx" } @@ -15,18 +14,18 @@ androidx-compose-ui = { module = "androidx.compose.ui:ui" } androidx-compose-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-compose" } androidx-compose-material3 = { module = "androidx.compose.material3:material3" } androidx-fragment = { module = "androidx.fragment:fragment-ktx" } -koltin-coroutines = { module ="org.jetbrains.kotlinx:kotlinx-coroutines-core" } +kotlin-coroutines = { module ="org.jetbrains.kotlinx:kotlinx-coroutines-core" } kotlin-immutable-collections = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlin-immutable-collections" } kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test" } +mlkit = { module = "com.google.mlkit:object-detection" , version.ref="mlkit" } mockk = { module = "io.mockk:mockk", version.ref = "mockk" } smile-id = { module = "com.smileidentity:smile-id", version.ref = "smile-id" } -smile-id-snapshot = { module = "com.smileidentity:smile-id", version.ref = "smile-id-snapshot" } - [plugins] android-application = { id = "com.android.application", version.ref = "android-gradle-plugin" } android-library = { id = "com.android.library", version.ref = "android-gradle-plugin" } +compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } flutter-plugin-loader = { id = "dev.flutter.flutter-plugin-loader", version.ref = "flutter-plugin-loader" } +flutter-gradle-plugin = { id = "dev.flutter.flutter-gradle-plugin" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } -kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint-plugin" } \ No newline at end of file From 9ad04c8f2e26e2bc2ede66390937d82431d3af13 Mon Sep 17 00:00:00 2001 From: Juma Allan Date: Mon, 9 Jun 2025 18:14:39 +0400 Subject: [PATCH 08/18] remove files from lib module --- android/settings.gradle.kts | 2 -- android/{lib => }/src/build.gradle.kts | 0 android/{lib => }/src/main/AndroidManifest.xml | 0 .../src/main/kotlin/com/smileidentity/flutter/Mapper.kt | 0 .../com/smileidentity/flutter/SmileComposablePlatformView.kt | 0 .../kotlin/com/smileidentity/flutter/SmileIDBiometricKYC.kt | 0 .../com/smileidentity/flutter/SmileIDDocumentCaptureView.kt | 0 .../com/smileidentity/flutter/SmileIDDocumentVerification.kt | 0 .../flutter/SmileIDEnhancedDocumentVerification.kt | 0 .../src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt | 0 .../smileidentity/flutter/SmileIDSmartSelfieAuthentication.kt | 0 .../com/smileidentity/flutter/SmileIDSmartSelfieCaptureView.kt | 0 .../com/smileidentity/flutter/SmileIDSmartSelfieEnrollment.kt | 0 .../smileidentity/flutter/SmileSelfieComposablePlatformView.kt | 0 .../enhanced/SmileIDSmartSelfieAuthenticationEnhanced.kt | 0 .../flutter/enhanced/SmileIDSmartSelfieEnrollmentEnhanced.kt | 0 .../com/smileidentity/flutter/generated/SmileIDMessages.g.kt | 0 .../com/smileidentity/flutter/results/DocumentCaptureResult.kt | 0 .../smileidentity/flutter/results/SmartSelfieCaptureResult.kt | 0 .../smileidentity/flutter/utils/DocumentCaptureResultAdapter.kt | 0 .../smileidentity/flutter/utils/SelfieCaptureResultAdapter.kt | 0 .../main/kotlin/com/smileidentity/flutter/utils/SmileIDUtils.kt | 0 .../test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt | 0 23 files changed, 2 deletions(-) rename android/{lib => }/src/build.gradle.kts (100%) rename android/{lib => }/src/main/AndroidManifest.xml (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/Mapper.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/SmileComposablePlatformView.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/SmileIDBiometricKYC.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentCaptureView.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentVerification.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/SmileIDEnhancedDocumentVerification.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieAuthentication.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieCaptureView.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieEnrollment.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/SmileSelfieComposablePlatformView.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieAuthenticationEnhanced.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieEnrollmentEnhanced.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/generated/SmileIDMessages.g.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/results/DocumentCaptureResult.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/results/SmartSelfieCaptureResult.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/utils/DocumentCaptureResultAdapter.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/utils/SelfieCaptureResultAdapter.kt (100%) rename android/{lib => }/src/main/kotlin/com/smileidentity/flutter/utils/SmileIDUtils.kt (100%) rename android/{lib => }/src/test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt (100%) diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index 8570d07..981b042 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -17,5 +17,3 @@ dependencyResolutionManagement { } } } - -include(":lib") diff --git a/android/lib/src/build.gradle.kts b/android/src/build.gradle.kts similarity index 100% rename from android/lib/src/build.gradle.kts rename to android/src/build.gradle.kts diff --git a/android/lib/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml similarity index 100% rename from android/lib/src/main/AndroidManifest.xml rename to android/src/main/AndroidManifest.xml diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/Mapper.kt b/android/src/main/kotlin/com/smileidentity/flutter/Mapper.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/Mapper.kt rename to android/src/main/kotlin/com/smileidentity/flutter/Mapper.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileComposablePlatformView.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileComposablePlatformView.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/SmileComposablePlatformView.kt rename to android/src/main/kotlin/com/smileidentity/flutter/SmileComposablePlatformView.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDBiometricKYC.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDBiometricKYC.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDBiometricKYC.kt rename to android/src/main/kotlin/com/smileidentity/flutter/SmileIDBiometricKYC.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentCaptureView.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentCaptureView.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentCaptureView.kt rename to android/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentCaptureView.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentVerification.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentVerification.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentVerification.kt rename to android/src/main/kotlin/com/smileidentity/flutter/SmileIDDocumentVerification.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDEnhancedDocumentVerification.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDEnhancedDocumentVerification.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDEnhancedDocumentVerification.kt rename to android/src/main/kotlin/com/smileidentity/flutter/SmileIDEnhancedDocumentVerification.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt rename to android/src/main/kotlin/com/smileidentity/flutter/SmileIDPlugin.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieAuthentication.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieAuthentication.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieAuthentication.kt rename to android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieAuthentication.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieCaptureView.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieCaptureView.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieCaptureView.kt rename to android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieCaptureView.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieEnrollment.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieEnrollment.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieEnrollment.kt rename to android/src/main/kotlin/com/smileidentity/flutter/SmileIDSmartSelfieEnrollment.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/SmileSelfieComposablePlatformView.kt b/android/src/main/kotlin/com/smileidentity/flutter/SmileSelfieComposablePlatformView.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/SmileSelfieComposablePlatformView.kt rename to android/src/main/kotlin/com/smileidentity/flutter/SmileSelfieComposablePlatformView.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieAuthenticationEnhanced.kt b/android/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieAuthenticationEnhanced.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieAuthenticationEnhanced.kt rename to android/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieAuthenticationEnhanced.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieEnrollmentEnhanced.kt b/android/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieEnrollmentEnhanced.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieEnrollmentEnhanced.kt rename to android/src/main/kotlin/com/smileidentity/flutter/enhanced/SmileIDSmartSelfieEnrollmentEnhanced.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/generated/SmileIDMessages.g.kt b/android/src/main/kotlin/com/smileidentity/flutter/generated/SmileIDMessages.g.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/generated/SmileIDMessages.g.kt rename to android/src/main/kotlin/com/smileidentity/flutter/generated/SmileIDMessages.g.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/results/DocumentCaptureResult.kt b/android/src/main/kotlin/com/smileidentity/flutter/results/DocumentCaptureResult.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/results/DocumentCaptureResult.kt rename to android/src/main/kotlin/com/smileidentity/flutter/results/DocumentCaptureResult.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/results/SmartSelfieCaptureResult.kt b/android/src/main/kotlin/com/smileidentity/flutter/results/SmartSelfieCaptureResult.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/results/SmartSelfieCaptureResult.kt rename to android/src/main/kotlin/com/smileidentity/flutter/results/SmartSelfieCaptureResult.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/utils/DocumentCaptureResultAdapter.kt b/android/src/main/kotlin/com/smileidentity/flutter/utils/DocumentCaptureResultAdapter.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/utils/DocumentCaptureResultAdapter.kt rename to android/src/main/kotlin/com/smileidentity/flutter/utils/DocumentCaptureResultAdapter.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/utils/SelfieCaptureResultAdapter.kt b/android/src/main/kotlin/com/smileidentity/flutter/utils/SelfieCaptureResultAdapter.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/utils/SelfieCaptureResultAdapter.kt rename to android/src/main/kotlin/com/smileidentity/flutter/utils/SelfieCaptureResultAdapter.kt diff --git a/android/lib/src/main/kotlin/com/smileidentity/flutter/utils/SmileIDUtils.kt b/android/src/main/kotlin/com/smileidentity/flutter/utils/SmileIDUtils.kt similarity index 100% rename from android/lib/src/main/kotlin/com/smileidentity/flutter/utils/SmileIDUtils.kt rename to android/src/main/kotlin/com/smileidentity/flutter/utils/SmileIDUtils.kt diff --git a/android/lib/src/test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt b/android/src/test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt similarity index 100% rename from android/lib/src/test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt rename to android/src/test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt From c33ba4e47aac2dd4a5d1bebccce91d00ef556718 Mon Sep 17 00:00:00 2001 From: Juma Allan Date: Mon, 9 Jun 2025 20:29:01 +0400 Subject: [PATCH 09/18] reworked gradle files to fix build failures --- android/build.gradle.kts | 77 ++++++++++++++++-- android/gradle/libs.versions.toml | 13 ++- android/src/build.gradle.kts | 72 ---------------- .../android/app/build.gradle.kts | 0 {example => sample}/android/build.gradle.kts | 7 -- .../android/gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 {example => sample}/android/gradlew | 0 {example => sample}/android/gradlew.bat | 0 9 files changed, 74 insertions(+), 95 deletions(-) delete mode 100644 android/src/build.gradle.kts rename {example => sample}/android/app/build.gradle.kts (100%) rename {example => sample}/android/build.gradle.kts (59%) rename {example => sample}/android/gradle/wrapper/gradle-wrapper.jar (100%) rename {example => sample}/android/gradle/wrapper/gradle-wrapper.properties (100%) rename {example => sample}/android/gradlew (100%) rename {example => sample}/android/gradlew.bat (100%) diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 7591c92..148dd30 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -1,15 +1,76 @@ plugins { - // Applied to all sub-modules + id("com.android.library") + id("org.jetbrains.kotlin.android") + alias(libs.plugins.ktlint) + alias(libs.plugins.compose.compiler) +} - // Applied depending on sub-module - alias(libs.plugins.android.library) apply false - alias(libs.plugins.compose.compiler) apply false - alias(libs.plugins.kotlin.android) apply false +allprojects { + repositories { + maven { url = uri("https://central.sonatype.com/repository/maven-snapshots/") } + } } -tasks.create("clean", Delete::class.java) { - delete(rootProject.layout.buildDirectory) +android { + namespace = "com.smileidentity.flutter" + compileSdk = 35 + + defaultConfig { + minSdk = 21 + + // Read version from pubspec.yaml for setWrapperInfo + val pubspecYaml = File("../pubspec.yaml") + val pubspecText = pubspecYaml.readText() + val versionRegex = Regex("""version:\s*(.+)""") + val versionMatch = versionRegex.find(pubspecText) + val version = if (versionMatch != null) { + pubspecText.split(Regex("""version:\s*"""))[1].split("\n")[0].trim() + } else { + "11.0.0" + } + buildConfigField("String", "SMILE_ID_VERSION", "\"$version\"") + } + + buildFeatures { + buildConfig = true + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = "17" + freeCompilerArgs += listOf("-Xskip-metadata-version-check") // metadata version check skip flag + } + + sourceSets { + getByName("main").java.srcDirs("src/main/kotlin") + getByName("test").java.srcDirs("src/test/kotlin") + } + + lint { + disable.add("NullSafeMutableLiveData") + } + + buildFeatures.compose = true +} + +dependencies { + implementation(libs.smileid) + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.compose.viewmodel) + implementation(libs.androidx.compose.material3) + implementation(libs.androidx.fragment) + implementation(libs.kotlin.coroutines) + implementation(libs.kotlin.immutable.collections) + implementation(libs.mlkit) + + testImplementation(libs.kotlin.test) + testImplementation(libs.mockk) } ktlint { @@ -17,4 +78,4 @@ ktlint { filter { exclude { it.file.path.contains(".g.kt") } } -} \ No newline at end of file +} diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index ed85be1..df966c8 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -1,12 +1,11 @@ [versions] android-gradle-plugin = "8.7.3" -flutter-plugin-loader = "1.0.0" -kotlin = "2.1.0" +kotlin = "2.1.21" kotlin-immutable-collections = "0.4.0" -ktlint-plugin = "12.1.2" -mockk = "1.13.13" +ktlint-plugin = "12.3.0" +mockk = "1.14.2" mlkit = "17.0.2" -smile-id = "11.0.3-20250609.065709-4" +smileid = "11.0.3" [libraries] androidx-core-ktx = { module = "androidx.core:core-ktx" } @@ -19,13 +18,11 @@ kotlin-immutable-collections = { module = "org.jetbrains.kotlinx:kotlinx-collect kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test" } mlkit = { module = "com.google.mlkit:object-detection" , version.ref="mlkit" } mockk = { module = "io.mockk:mockk", version.ref = "mockk" } -smile-id = { module = "com.smileidentity:smile-id", version.ref = "smile-id" } +smileid = { module = "com.smileidentity:android-sdk", version.ref = "smileid" } [plugins] android-application = { id = "com.android.application", version.ref = "android-gradle-plugin" } -android-library = { id = "com.android.library", version.ref = "android-gradle-plugin" } compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } -flutter-plugin-loader = { id = "dev.flutter.flutter-plugin-loader", version.ref = "flutter-plugin-loader" } flutter-gradle-plugin = { id = "dev.flutter.flutter-gradle-plugin" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint-plugin" } \ No newline at end of file diff --git a/android/src/build.gradle.kts b/android/src/build.gradle.kts deleted file mode 100644 index 40744b4..0000000 --- a/android/src/build.gradle.kts +++ /dev/null @@ -1,72 +0,0 @@ -plugins { - alias(libs.plugins.android.library) - alias(libs.plugins.kotlin.android) - alias(libs.plugins.ktlint) - alias(libs.plugins.compose.compiler) -} - -android { - namespace = "com.smileidentity.flutter" - compileSdk = 35 - - defaultConfig { - minSdk = 21 - - // Read version from pubspec.yaml for setWrapperInfo - val pubspecYaml = File("../pubspec.yaml") - val pubspecText = pubspecYaml.readText() - val versionRegex = Regex("""version:\s*(.+)""") - val versionMatch = versionRegex.find(pubspecText) - val version = if (versionMatch != null) { - pubspecText.split(Regex("""version:\s*"""))[1].split("\n")[0].trim() - } else { - "11.0.0" - } - buildConfigField("String", "SMILE_ID_VERSION", "\"$version\"") - } - - buildFeatures { - buildConfig = true - } - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 - } - - kotlinOptions { - jvmTarget = "17" - freeCompilerArgs += listOf("-Xskip-metadata-version-check") // metadata version check skip flag - } - - sourceSets { - getByName("main").java.srcDirs("src/main/kotlin") - getByName("test").java.srcDirs("src/test/kotlin") - } - - lint { - disable.add("NullSafeMutableLiveData") - } - - buildFeatures.compose = true - if (!kotlinVersion.startsWith("2")) { - composeOptions { - kotlinCompilerExtensionVersion = kotlinCompilerExtension - } - } -} - -dependencies { - implementation(libs.smile.id) - implementation(libs.androidx.core.ktx) - implementation(libs.androidx.compose.ui) - implementation(libs.androidx.compose.viewmodel) - implementation(libs.androidx.compose.material3) - implementation(libs.androidx.fragment) - implementation(libs.kotlin.coroutines) - implementation(libs.kotlin.immutable.collections) - implementation(libs.mlkit) - - testImplementation(libs.kotlin.test) - testImplementation(libs.mockk) -} diff --git a/example/android/app/build.gradle.kts b/sample/android/app/build.gradle.kts similarity index 100% rename from example/android/app/build.gradle.kts rename to sample/android/app/build.gradle.kts diff --git a/example/android/build.gradle.kts b/sample/android/build.gradle.kts similarity index 59% rename from example/android/build.gradle.kts rename to sample/android/build.gradle.kts index 5e6a67a..90df827 100644 --- a/example/android/build.gradle.kts +++ b/sample/android/build.gradle.kts @@ -1,10 +1,3 @@ -plugins { - alias(libs.plugins.android.application) apply false - alias(libs.plugins.kotlin.android) apply false - alias(libs.plugins.ktlint) apply false - alias(libs.plugins.flutter.plugin.loader) apply false -} - rootProject.layout.buildDirectory.set(file("../build")) subprojects { diff --git a/example/android/gradle/wrapper/gradle-wrapper.jar b/sample/android/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from example/android/gradle/wrapper/gradle-wrapper.jar rename to sample/android/gradle/wrapper/gradle-wrapper.jar diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/sample/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from example/android/gradle/wrapper/gradle-wrapper.properties rename to sample/android/gradle/wrapper/gradle-wrapper.properties diff --git a/example/android/gradlew b/sample/android/gradlew similarity index 100% rename from example/android/gradlew rename to sample/android/gradlew diff --git a/example/android/gradlew.bat b/sample/android/gradlew.bat similarity index 100% rename from example/android/gradlew.bat rename to sample/android/gradlew.bat From 2cc8e91ac8f14082e3f7ee601906eb94e5f0f3e4 Mon Sep 17 00:00:00 2001 From: Juma Allan Date: Mon, 9 Jun 2025 20:29:37 +0400 Subject: [PATCH 10/18] migrate from example to sample --- .github/workflows/build.yaml | 14 +-- .github/workflows/release_ios.yml | 4 +- .gitignore | 2 +- CONTRIBUTING.md | 4 +- android/settings.gradle.kts | 18 ---- .../flutter/SmileIDPluginTest.kt | 4 +- example/android/gradle.properties | 5 - ios/smile_id.podspec | 4 +- {example => sample}/.gitignore | 0 {example => sample}/README.md | 0 {example => sample}/analysis_options.yaml | 0 {example => sample}/android/.gitignore | 0 .../android/app/src/debug/AndroidManifest.xml | 0 .../android/app/src/main/AndroidManifest.xml | 0 .../android/app/src/main/assets/.gitignore | 0 .../flutter/sample/MainActivity.kt | 0 .../res/drawable-v21/launch_background.xml | 0 .../main/res/drawable/launch_background.xml | 0 .../src/main/res/mipmap-hdpi/ic_launcher.webp | Bin .../src/main/res/mipmap-mdpi/ic_launcher.webp | Bin .../main/res/mipmap-xhdpi/ic_launcher.webp | Bin .../main/res/mipmap-xxhdpi/ic_launcher.webp | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.webp | Bin .../app/src/main/res/values-night/styles.xml | 0 .../app/src/main/res/values/styles.xml | 0 .../app/src/profile/AndroidManifest.xml | 0 sample/android/gradle.properties | 14 +++ .../android/settings.gradle.kts | 7 ++ .../plugin_integration_test.dart | 0 {example => sample}/ios/.gitignore | 0 .../ios/Flutter/AppFrameworkInfo.plist | 0 .../ios/Flutter/Debug.xcconfig | 0 .../ios/Flutter/Release.xcconfig | 0 {example => sample}/ios/Podfile | 0 {example => sample}/ios/Podfile.lock | 0 .../ios/Runner.xcodeproj/project.pbxproj | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 .../xcshareddata/xcschemes/Runner.xcscheme | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/WorkspaceSettings.xcsettings | 0 .../ios/Runner/AppDelegate.swift | 0 .../AppIcon.appiconset/Contents.json | 0 .../Icon-App-1024x1024@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin .../Icon-App-83.5x83.5@2x.png | Bin .../LaunchImage.imageset/Contents.json | 0 .../LaunchImage.imageset/LaunchImage.png | Bin .../LaunchImage.imageset/LaunchImage@2x.png | Bin .../LaunchImage.imageset/LaunchImage@3x.png | Bin .../LaunchImage.imageset/README.md | 0 .../Runner/Base.lproj/LaunchScreen.storyboard | 0 .../ios/Runner/Base.lproj/Main.storyboard | 0 {example => sample}/ios/Runner/Info.plist | 2 +- .../ios/Runner/Runner-Bridging-Header.h | 0 .../ios/RunnerTests/RunnerTests.swift | 0 {example => sample}/lib/main.dart | 0 {example => sample}/pubspec.lock | 92 +++++++++--------- {example => sample}/pubspec.yaml | 2 +- {example => sample}/test/widget_test.dart | 2 +- 74 files changed, 86 insertions(+), 88 deletions(-) delete mode 100644 example/android/gradle.properties rename {example => sample}/.gitignore (100%) rename {example => sample}/README.md (100%) rename {example => sample}/analysis_options.yaml (100%) rename {example => sample}/android/.gitignore (100%) rename {example => sample}/android/app/src/debug/AndroidManifest.xml (100%) rename {example => sample}/android/app/src/main/AndroidManifest.xml (100%) rename {example => sample}/android/app/src/main/assets/.gitignore (100%) rename {example => sample}/android/app/src/main/kotlin/com/smileidentity/flutter/sample/MainActivity.kt (100%) rename {example => sample}/android/app/src/main/res/drawable-v21/launch_background.xml (100%) rename {example => sample}/android/app/src/main/res/drawable/launch_background.xml (100%) rename {example => sample}/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp (100%) rename {example => sample}/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp (100%) rename {example => sample}/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp (100%) rename {example => sample}/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp (100%) rename {example => sample}/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp (100%) rename {example => sample}/android/app/src/main/res/values-night/styles.xml (100%) rename {example => sample}/android/app/src/main/res/values/styles.xml (100%) rename {example => sample}/android/app/src/profile/AndroidManifest.xml (100%) create mode 100644 sample/android/gradle.properties rename {example => sample}/android/settings.gradle.kts (72%) rename {example => sample}/integration_test/plugin_integration_test.dart (100%) rename {example => sample}/ios/.gitignore (100%) rename {example => sample}/ios/Flutter/AppFrameworkInfo.plist (100%) rename {example => sample}/ios/Flutter/Debug.xcconfig (100%) rename {example => sample}/ios/Flutter/Release.xcconfig (100%) rename {example => sample}/ios/Podfile (100%) rename {example => sample}/ios/Podfile.lock (100%) rename {example => sample}/ios/Runner.xcodeproj/project.pbxproj (100%) rename {example => sample}/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename {example => sample}/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename {example => sample}/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%) rename {example => sample}/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (100%) rename {example => sample}/ios/Runner.xcworkspace/contents.xcworkspacedata (100%) rename {example => sample}/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename {example => sample}/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings (100%) rename {example => sample}/ios/Runner/AppDelegate.swift (100%) rename {example => sample}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {example => sample}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json (100%) rename {example => sample}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png (100%) rename {example => sample}/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md (100%) rename {example => sample}/ios/Runner/Base.lproj/LaunchScreen.storyboard (100%) rename {example => sample}/ios/Runner/Base.lproj/Main.storyboard (100%) rename {example => sample}/ios/Runner/Info.plist (98%) rename {example => sample}/ios/Runner/Runner-Bridging-Header.h (100%) rename {example => sample}/ios/RunnerTests/RunnerTests.swift (100%) rename {example => sample}/lib/main.dart (100%) rename {example => sample}/pubspec.lock (71%) rename {example => sample}/pubspec.yaml (90%) rename {example => sample}/test/widget_test.dart (90%) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index dd22df8..46ca162 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -19,7 +19,7 @@ jobs: flutter-version: '3.29.3' # Set the desired Flutter version here channel: 'stable' - name: Install Dependencies - run: flutter pub get && cd example && flutter pub get && cd .. + run: flutter pub get && cd sample && flutter pub get && cd .. - name: Lint Flutter run: flutter analyze Android: @@ -41,7 +41,7 @@ jobs: flutter-version: ${{ matrix.flutter-version }} channel: 'stable' - name: Install Dependencies - run: flutter pub get && cd example && flutter pub get && cd .. + run: flutter pub get && cd sample && flutter pub get && cd .. - name: Lint Android uses: musichin/ktlint-check@v3 with: @@ -51,16 +51,16 @@ jobs: !**/**.g.kt !**/generated/** - name: Test - run: flutter test && cd example && flutter test && cd .. + run: flutter test && cd sample && flutter test && cd .. - name: Build Android Sample App - run: cd example && flutter build apk && cd .. + run: cd sample && flutter build apk && cd .. iOS: # TODO: Change back to macos-latest once it points to macOS 14 (Q2 '24) runs-on: macos-14 timeout-minutes: 10 steps: - uses: actions/checkout@v4 - - run: touch example/ios/smile_config.json + - run: touch sample/ios/smile_config.json - uses: subosito/flutter-action@v2 with: flutter-version: '3.29.3' # Set the desired Flutter version here @@ -70,6 +70,6 @@ jobs: with: version: 1.14.3 - name: Install Dependencies - run: flutter pub get && cd example && flutter pub get && cd .. + run: flutter pub get && cd sample && flutter pub get && cd .. - name: Build iOS Sample App - run: cd example/ios && pod install && flutter build ios --no-codesign && cd .. + run: cd sample/ios && pod install && flutter build ios --no-codesign && cd .. diff --git a/.github/workflows/release_ios.yml b/.github/workflows/release_ios.yml index 80293b1..a4c2d81 100644 --- a/.github/workflows/release_ios.yml +++ b/.github/workflows/release_ios.yml @@ -25,7 +25,7 @@ jobs: run: | sed -i "s/s.version\s*=\s*'[^']*'/s.version = '$(echo "${{ github.event.inputs.ios_release_version }}" | cut -c 2-)'/g" ios/smile_id.podspec sed -i "s/s.dependency\s*'SmileID'\s*,\s*'[^']*'/s.dependency 'SmileID', '$(echo "${{ github.event.inputs.ios_release_version }}" | cut -c 2-)'/g" ios/smile_id.podspec - cd example/ios + cd sample/ios pod update smile_id SmileID - name: Commit and Push Changes run: | @@ -33,7 +33,7 @@ jobs: git config user.email "actions@github.com" git add ios/smile_id.podspec - git add example/ios/Podfile.lock + git add sample/ios/Podfile.lock git commit -m "Update iOS SDK version to ${{ github.event.inputs.ios_release_version }}" git push --set-upstream origin "ios-${{ github.event.inputs.ios_release_version }}" - name: Create Pull Request diff --git a/.gitignore b/.gitignore index 05716d6..5b9c7d0 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,4 @@ build/ .fvm/ smile_config.json -example/android/app/.cxx \ No newline at end of file +sample/android/app/.cxx \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d6005d7..4c21a7c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,11 +48,11 @@ Open the `sample` folder, then open the `ios` folder. Run the following commands ```ruby # s.dependency "SmileID" # => Mind the version removal ``` -* Specify the repo SmileID [iOS](https://github.com/smileidentity/ios) repo and pick a tag or branch podspec file in the Podfile example/ios/Podfile file: +* Specify the repo SmileID [iOS](https://github.com/smileidentity/ios) repo and pick a tag or branch podspec file in the Podfile sample/ios/Podfile file: ```ruby pod 'SmileID', git: 'https://github.com/smileidentity/ios.git', branch: 'main' ``` -* Run `pod install` in the `example/ios` folder +* Run `pod install` in the `sample/ios` folder * If you have pod install issues run ```bash pod deintegrate && pod install diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index 981b042..d350ccf 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -1,19 +1 @@ rootProject.name = "smile_id_flutter" - -pluginManagement { - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -dependencyResolutionManagement { - repositories { - google() - mavenCentral() - maven { - url = uri("https://central.sonatype.com/repository/maven-snapshots/") - } - } -} diff --git a/android/src/test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt b/android/src/test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt index ce5035a..c58879d 100644 --- a/android/src/test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt +++ b/android/src/test/kotlin/com/smileidentity/flutter/SmileIDPluginTest.kt @@ -14,8 +14,8 @@ import kotlin.test.Test /* * This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation. * - * Once you have built the plugin's example app, you can run these tests from the command - * line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or + * Once you have built the plugin's sample app, you can run these tests from the command + * line by running `./gradlew testDebugUnitTest` in the `sample/android/` directory, or * you can run them directly from IDEs that support JUnit such as Android Studio. */ internal class SmileIDPluginTest { diff --git a/example/android/gradle.properties b/example/android/gradle.properties deleted file mode 100644 index f93b85b..0000000 --- a/example/android/gradle.properties +++ /dev/null @@ -1,5 +0,0 @@ -org.gradle.jvmargs=-Xmx1536M -android.useAndroidX=true -android.enableJetifier=true -# TODO https://stackoverflow.com/a/76159929 -kotlin.jvm.target.validation.mode = IGNORE diff --git a/ios/smile_id.podspec b/ios/smile_id.podspec index 7394d38..d6622b9 100644 --- a/ios/smile_id.podspec +++ b/ios/smile_id.podspec @@ -13,8 +13,8 @@ Pod::Spec.new do |s| s.source_files = 'Classes/**/*' s.dependency 'Flutter' s.dependency 'SmileID', '11.0.0' - # for development alongside example/ios/Podfile uncomment the version and specify - # tag or branch in example/ios/Podfile + # for development alongside sample/ios/Podfile uncomment the version and specify + # tag or branch in sample/ios/Podfile # s.dependency "SmileID" s.platform = :ios, '13.0' diff --git a/example/.gitignore b/sample/.gitignore similarity index 100% rename from example/.gitignore rename to sample/.gitignore diff --git a/example/README.md b/sample/README.md similarity index 100% rename from example/README.md rename to sample/README.md diff --git a/example/analysis_options.yaml b/sample/analysis_options.yaml similarity index 100% rename from example/analysis_options.yaml rename to sample/analysis_options.yaml diff --git a/example/android/.gitignore b/sample/android/.gitignore similarity index 100% rename from example/android/.gitignore rename to sample/android/.gitignore diff --git a/example/android/app/src/debug/AndroidManifest.xml b/sample/android/app/src/debug/AndroidManifest.xml similarity index 100% rename from example/android/app/src/debug/AndroidManifest.xml rename to sample/android/app/src/debug/AndroidManifest.xml diff --git a/example/android/app/src/main/AndroidManifest.xml b/sample/android/app/src/main/AndroidManifest.xml similarity index 100% rename from example/android/app/src/main/AndroidManifest.xml rename to sample/android/app/src/main/AndroidManifest.xml diff --git a/example/android/app/src/main/assets/.gitignore b/sample/android/app/src/main/assets/.gitignore similarity index 100% rename from example/android/app/src/main/assets/.gitignore rename to sample/android/app/src/main/assets/.gitignore diff --git a/example/android/app/src/main/kotlin/com/smileidentity/flutter/sample/MainActivity.kt b/sample/android/app/src/main/kotlin/com/smileidentity/flutter/sample/MainActivity.kt similarity index 100% rename from example/android/app/src/main/kotlin/com/smileidentity/flutter/sample/MainActivity.kt rename to sample/android/app/src/main/kotlin/com/smileidentity/flutter/sample/MainActivity.kt diff --git a/example/android/app/src/main/res/drawable-v21/launch_background.xml b/sample/android/app/src/main/res/drawable-v21/launch_background.xml similarity index 100% rename from example/android/app/src/main/res/drawable-v21/launch_background.xml rename to sample/android/app/src/main/res/drawable-v21/launch_background.xml diff --git a/example/android/app/src/main/res/drawable/launch_background.xml b/sample/android/app/src/main/res/drawable/launch_background.xml similarity index 100% rename from example/android/app/src/main/res/drawable/launch_background.xml rename to sample/android/app/src/main/res/drawable/launch_background.xml diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/sample/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp similarity index 100% rename from example/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp rename to sample/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/sample/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp similarity index 100% rename from example/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp rename to sample/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp diff --git a/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/sample/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp similarity index 100% rename from example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp rename to sample/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/sample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp similarity index 100% rename from example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp rename to sample/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/sample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp similarity index 100% rename from example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp rename to sample/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp diff --git a/example/android/app/src/main/res/values-night/styles.xml b/sample/android/app/src/main/res/values-night/styles.xml similarity index 100% rename from example/android/app/src/main/res/values-night/styles.xml rename to sample/android/app/src/main/res/values-night/styles.xml diff --git a/example/android/app/src/main/res/values/styles.xml b/sample/android/app/src/main/res/values/styles.xml similarity index 100% rename from example/android/app/src/main/res/values/styles.xml rename to sample/android/app/src/main/res/values/styles.xml diff --git a/example/android/app/src/profile/AndroidManifest.xml b/sample/android/app/src/profile/AndroidManifest.xml similarity index 100% rename from example/android/app/src/profile/AndroidManifest.xml rename to sample/android/app/src/profile/AndroidManifest.xml diff --git a/sample/android/gradle.properties b/sample/android/gradle.properties new file mode 100644 index 0000000..3f00751 --- /dev/null +++ b/sample/android/gradle.properties @@ -0,0 +1,14 @@ +org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +android.enableJetifier=false +android.useAndroidX=true + +# TODO https://stackoverflow.com/a/76159929 +kotlin.jvm.target.validation.mode = IGNORE + +# Enable Gradle daemon and parallel builds +org.gradle.daemon=true +org.gradle.parallel=true +org.gradle.configureondemand=true + +# Enable caching +org.gradle.caching=true diff --git a/example/android/settings.gradle.kts b/sample/android/settings.gradle.kts similarity index 72% rename from example/android/settings.gradle.kts rename to sample/android/settings.gradle.kts index 4edc714..c68c4f1 100644 --- a/example/android/settings.gradle.kts +++ b/sample/android/settings.gradle.kts @@ -20,6 +20,7 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + maven { url = uri("https://central.sonatype.com/repository/maven-snapshots/") } } versionCatalogs { @@ -29,4 +30,10 @@ dependencyResolutionManagement { } } +plugins { + id("com.android.application") version "8.7.3" apply false + id("org.jetbrains.kotlin.android") version "2.1.21" apply false + id("dev.flutter.flutter-plugin-loader") version "1.0.0" +} + include(":app") diff --git a/example/integration_test/plugin_integration_test.dart b/sample/integration_test/plugin_integration_test.dart similarity index 100% rename from example/integration_test/plugin_integration_test.dart rename to sample/integration_test/plugin_integration_test.dart diff --git a/example/ios/.gitignore b/sample/ios/.gitignore similarity index 100% rename from example/ios/.gitignore rename to sample/ios/.gitignore diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/sample/ios/Flutter/AppFrameworkInfo.plist similarity index 100% rename from example/ios/Flutter/AppFrameworkInfo.plist rename to sample/ios/Flutter/AppFrameworkInfo.plist diff --git a/example/ios/Flutter/Debug.xcconfig b/sample/ios/Flutter/Debug.xcconfig similarity index 100% rename from example/ios/Flutter/Debug.xcconfig rename to sample/ios/Flutter/Debug.xcconfig diff --git a/example/ios/Flutter/Release.xcconfig b/sample/ios/Flutter/Release.xcconfig similarity index 100% rename from example/ios/Flutter/Release.xcconfig rename to sample/ios/Flutter/Release.xcconfig diff --git a/example/ios/Podfile b/sample/ios/Podfile similarity index 100% rename from example/ios/Podfile rename to sample/ios/Podfile diff --git a/example/ios/Podfile.lock b/sample/ios/Podfile.lock similarity index 100% rename from example/ios/Podfile.lock rename to sample/ios/Podfile.lock diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/sample/ios/Runner.xcodeproj/project.pbxproj similarity index 100% rename from example/ios/Runner.xcodeproj/project.pbxproj rename to sample/ios/Runner.xcodeproj/project.pbxproj diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/sample/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to sample/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/sample/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to sample/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/sample/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to sample/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/sample/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme similarity index 100% rename from example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to sample/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/sample/ios/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from example/ios/Runner.xcworkspace/contents.xcworkspacedata rename to sample/ios/Runner.xcworkspace/contents.xcworkspacedata diff --git a/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/sample/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to sample/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/sample/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to sample/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/example/ios/Runner/AppDelegate.swift b/sample/ios/Runner/AppDelegate.swift similarity index 100% rename from example/ios/Runner/AppDelegate.swift rename to sample/ios/Runner/AppDelegate.swift diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png rename to sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png rename to sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png rename to sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png rename to sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png rename to sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png rename to sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png rename to sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png rename to sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png rename to sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png rename to sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png rename to sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png rename to sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png rename to sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png rename to sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png rename to sample/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/sample/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json similarity index 100% rename from example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json rename to sample/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/sample/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png rename to sample/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/sample/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png rename to sample/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/sample/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png similarity index 100% rename from example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png rename to sample/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/sample/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md similarity index 100% rename from example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md rename to sample/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md diff --git a/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/sample/ios/Runner/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from example/ios/Runner/Base.lproj/LaunchScreen.storyboard rename to sample/ios/Runner/Base.lproj/LaunchScreen.storyboard diff --git a/example/ios/Runner/Base.lproj/Main.storyboard b/sample/ios/Runner/Base.lproj/Main.storyboard similarity index 100% rename from example/ios/Runner/Base.lproj/Main.storyboard rename to sample/ios/Runner/Base.lproj/Main.storyboard diff --git a/example/ios/Runner/Info.plist b/sample/ios/Runner/Info.plist similarity index 98% rename from example/ios/Runner/Info.plist rename to sample/ios/Runner/Info.plist index 23139d2..da39ccc 100644 --- a/example/ios/Runner/Info.plist +++ b/sample/ios/Runner/Info.plist @@ -15,7 +15,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - smileid_example + smileid_sample CFBundlePackageType APPL CFBundleShortVersionString diff --git a/example/ios/Runner/Runner-Bridging-Header.h b/sample/ios/Runner/Runner-Bridging-Header.h similarity index 100% rename from example/ios/Runner/Runner-Bridging-Header.h rename to sample/ios/Runner/Runner-Bridging-Header.h diff --git a/example/ios/RunnerTests/RunnerTests.swift b/sample/ios/RunnerTests/RunnerTests.swift similarity index 100% rename from example/ios/RunnerTests/RunnerTests.swift rename to sample/ios/RunnerTests/RunnerTests.swift diff --git a/example/lib/main.dart b/sample/lib/main.dart similarity index 100% rename from example/lib/main.dart rename to sample/lib/main.dart diff --git a/example/pubspec.lock b/sample/pubspec.lock similarity index 71% rename from example/pubspec.lock rename to sample/pubspec.lock index d927aed..7e224cf 100644 --- a/example/pubspec.lock +++ b/sample/pubspec.lock @@ -5,42 +5,42 @@ packages: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.13.0" boolean_selector: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" characters: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" clock: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.1" cupertino_icons: dependency: "direct main" description: @@ -53,18 +53,18 @@ packages: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.3" file: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" flutter: dependency: "direct main" description: flutter @@ -102,18 +102,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.9" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.9" leak_tracker_testing: dependency: transitive description: @@ -134,10 +134,10 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -150,26 +150,26 @@ packages: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.16.0" path: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" platform: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -182,15 +182,15 @@ packages: dependency: transitive description: name: process - sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" + sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" url: "https://pub.dev" source: hosted - version: "5.0.2" + version: "5.0.3" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" smile_id: dependency: "direct main" description: @@ -202,34 +202,34 @@ packages: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.10.1" stack_trace: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.4.1" sync_http: dependency: transitive description: @@ -242,18 +242,18 @@ packages: dependency: transitive description: name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test_api: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.4" vector_math: dependency: transitive description: @@ -266,18 +266,18 @@ packages: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "15.0.0" webdriver: dependency: transitive description: name: webdriver - sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" + sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.1.0" sdks: - dart: ">=3.3.0 <4.0.0" + dart: ">=3.7.0-0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/example/pubspec.yaml b/sample/pubspec.yaml similarity index 90% rename from example/pubspec.yaml rename to sample/pubspec.yaml index 2abec66..1b3c99a 100644 --- a/example/pubspec.yaml +++ b/sample/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: smile_id: # When depending on this package from a real application you should use: # smile_id: ^x.y.z - # The example app is bundled with the plugin so we use a path dependency on + # The sample app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ diff --git a/example/test/widget_test.dart b/sample/test/widget_test.dart similarity index 90% rename from example/test/widget_test.dart rename to sample/test/widget_test.dart index bc4107b..a09e600 100644 --- a/example/test/widget_test.dart +++ b/sample/test/widget_test.dart @@ -1,7 +1,7 @@ // This is a basic Flutter widget test. // // To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll +// utility in the flutter_test package. For sample, you can send tap and scroll // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. From 0acb7a7d8ef24f59022bcafed72c87ce58cf87d2 Mon Sep 17 00:00:00 2001 From: Juma Allan Date: Mon, 9 Jun 2025 20:32:48 +0400 Subject: [PATCH 11/18] updated dependencies --- sample/ios/Podfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sample/ios/Podfile.lock b/sample/ios/Podfile.lock index 81aeae3..cf0d138 100644 --- a/sample/ios/Podfile.lock +++ b/sample/ios/Podfile.lock @@ -43,9 +43,9 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: FingerprintJS: 3a0c3e7f5035ecae199e5e5836200d9b20f1266a Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 + integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e lottie-ios: 96784afc26ea031d3e2b6cae342a4b8915072489 - smile_id: 7c77a15b27a01a4bc03ca3971bba25cdc2ba8cc9 + smile_id: 6a7e895fb577400ad37cd570b42a1f2bba98c345 SmileID: 3b44f5c41f8050f57bb77a9d44df5d5e9d3ffe22 SmileIDSecurity: b847101f7d7b86c1c453fb1b045146dfcbc5183d ZIPFoundation: b8c29ea7ae353b309bc810586181fd073cb3312c From 4eadf6241f10ca473a2bcbc3cdd1c29266566bd6 Mon Sep 17 00:00:00 2001 From: Harun Wangereka Date: Tue, 10 Jun 2025 12:30:02 +0300 Subject: [PATCH 12/18] Readd kotlin version checks and fallback to old Compose compiler setup --- android/build.gradle.kts | 59 ++++++++++++++++++++++-------- android/gradle/libs.versions.toml | 3 +- sample/android/settings.gradle.kts | 2 +- 3 files changed, 45 insertions(+), 19 deletions(-) diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 148dd30..1834839 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -1,17 +1,41 @@ -plugins { - id("com.android.library") - id("org.jetbrains.kotlin.android") +val kotlinVersion = findProperty("kotlinVersion") as String? ?: "2.1.0" +val kotlinCompilerExtension = findProperty("kotlinCompilerExtensionVersion") as String? ?: "1.5.14" - alias(libs.plugins.ktlint) - alias(libs.plugins.compose.compiler) +extra.apply { + set("kotlinVersion", kotlinVersion) + set("kotlinCompilerExtension", kotlinCompilerExtension) +} + +buildscript { + val kotlinVersion = rootProject.findProperty("kotlinVersion") as String? ?: "2.1.0" + + dependencies { + if (kotlinVersion.startsWith("2")) { + classpath("org.jetbrains.kotlin:compose-compiler-gradle-plugin:$kotlinVersion") + } else { + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") + } + } } allprojects { repositories { - maven { url = uri("https://central.sonatype.com/repository/maven-snapshots/") } + maven { + url = uri("https://central.sonatype.com/repository/maven-snapshots/") + } } } +plugins { + id("com.android.library") + id("org.jetbrains.kotlin.android") + alias(libs.plugins.ktlint) +} + +if (kotlinVersion.startsWith("2")) { + apply(plugin = "org.jetbrains.kotlin.plugin.compose") +} + android { namespace = "com.smileidentity.flutter" compileSdk = 35 @@ -22,9 +46,8 @@ android { // Read version from pubspec.yaml for setWrapperInfo val pubspecYaml = File("../pubspec.yaml") val pubspecText = pubspecYaml.readText() - val versionRegex = Regex("""version:\s*(.+)""") - val versionMatch = versionRegex.find(pubspecText) - val version = if (versionMatch != null) { + val versionLine = Regex("""version:\s*(.+)""").find(pubspecText) + val version = if (versionLine != null) { pubspecText.split(Regex("""version:\s*"""))[1].split("\n")[0].trim() } else { "11.0.0" @@ -32,10 +55,6 @@ android { buildConfigField("String", "SMILE_ID_VERSION", "\"$version\"") } - buildFeatures { - buildConfig = true - } - compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 @@ -47,15 +66,23 @@ android { } sourceSets { - getByName("main").java.srcDirs("src/main/kotlin") - getByName("test").java.srcDirs("src/test/kotlin") + sourceSets["main"].java.srcDirs("src/main/kotlin") + sourceSets["test"].java.srcDirs("src/test/kotlin") } lint { disable.add("NullSafeMutableLiveData") } - buildFeatures.compose = true + buildFeatures { + buildConfig = true + compose = true + } + if (!kotlinVersion.startsWith("2")) { + composeOptions { + kotlinCompilerExtensionVersion = kotlinCompilerExtension + } + } } dependencies { diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index df966c8..65a3bd7 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -android-gradle-plugin = "8.7.3" +android-gradle-plugin = "8.10.1" kotlin = "2.1.21" kotlin-immutable-collections = "0.4.0" ktlint-plugin = "12.3.0" @@ -22,7 +22,6 @@ smileid = { module = "com.smileidentity:android-sdk", version.ref = "smileid" } [plugins] android-application = { id = "com.android.application", version.ref = "android-gradle-plugin" } -compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } flutter-gradle-plugin = { id = "dev.flutter.flutter-gradle-plugin" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint-plugin" } \ No newline at end of file diff --git a/sample/android/settings.gradle.kts b/sample/android/settings.gradle.kts index c68c4f1..10eaa47 100644 --- a/sample/android/settings.gradle.kts +++ b/sample/android/settings.gradle.kts @@ -31,7 +31,7 @@ dependencyResolutionManagement { } plugins { - id("com.android.application") version "8.7.3" apply false + id("com.android.application") version "8.10.1" apply false id("org.jetbrains.kotlin.android") version "2.1.21" apply false id("dev.flutter.flutter-plugin-loader") version "1.0.0" } From f3a9167ffeb48c0fc323821327c2d0fa3882a37c Mon Sep 17 00:00:00 2001 From: Harun Wangereka Date: Tue, 10 Jun 2025 13:04:33 +0300 Subject: [PATCH 13/18] Update changelog --- CHANGELOG.md | 10 ++++++++++ android/build.gradle.kts | 4 +++- sample/android/app/build.gradle.kts | 20 +++++++++----------- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b8743d..ad2bcdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Release Notes +## 11.0.2 + +### Chnaged +* Renamed **exmaple** folder to **sample** and replaced all usages of example in the project. +* Migrate all gradle files in the sample and SDK folders from Groovy to Kotlin. +* Add a `libs.versions.toml` file to share dependencies between the sample project and the Android SDK. +* Cleanup and minor code improvements on the gradlew files. +* Update Android Gradle Plugin and Kotlin version to the latest. +* Fail the `assemble` gradle task when `smile_config.json` file is not added in the assets folder. + ## 11.0.1 ### Fixed diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 1834839..fc56d9a 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -62,7 +62,9 @@ android { kotlinOptions { jvmTarget = "17" - freeCompilerArgs += listOf("-Xskip-metadata-version-check") // metadata version check skip flag + freeCompilerArgs += listOf( + "-Xskip-metadata-version-check", + ) // metadata version check skip flag } sourceSets { diff --git a/sample/android/app/build.gradle.kts b/sample/android/app/build.gradle.kts index ef880e9..a53df1f 100644 --- a/sample/android/app/build.gradle.kts +++ b/sample/android/app/build.gradle.kts @@ -31,18 +31,16 @@ android { jvmTarget = "17" freeCompilerArgs += listOf("-Xskip-metadata-version-check") } - - val checkSmileConfigFileTaskName = "checkSmileConfigFile" - tasks.register(checkSmileConfigFileTaskName) { - doLast { - val configFile = file("src/main/assets/smile_config.json") - if (configFile.readText().isBlank()) { - throw IllegalArgumentException("Empty smile_config.json file in src/main/assets!") - } +} +val checkSmileConfigFileTask = tasks.register("checkSmileConfigFile") { + doLast { + val configFile = file("src/main/assets/smile_config.json") + if (configFile.readText().isBlank()) { + throw IllegalArgumentException("Empty smile_config.json file in src/main/assets!") } } +} - tasks.named("assemble") { - dependsOn(checkSmileConfigFileTaskName) - } +tasks.named("assemble") { + dependsOn(checkSmileConfigFileTask) } From fd46aa761d7ed85ff3e104b0dedf28c7649eba8c Mon Sep 17 00:00:00 2001 From: Harun Wangereka Date: Tue, 10 Jun 2025 15:33:38 +0300 Subject: [PATCH 14/18] fix flutter run issues --- android/gradle/libs.versions.toml | 4 ++-- sample/android/app/build.gradle.kts | 6 +++--- sample/android/build.gradle.kts | 14 +++++++++++--- sample/android/settings.gradle.kts | 8 ++++---- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index 65a3bd7..7b855ca 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] -android-gradle-plugin = "8.10.1" -kotlin = "2.1.21" +android-gradle-plugin = "8.7.3" +kotlin = "2.1.0" kotlin-immutable-collections = "0.4.0" ktlint-plugin = "12.3.0" mockk = "1.14.2" diff --git a/sample/android/app/build.gradle.kts b/sample/android/app/build.gradle.kts index a53df1f..19d081c 100644 --- a/sample/android/app/build.gradle.kts +++ b/sample/android/app/build.gradle.kts @@ -1,7 +1,7 @@ plugins { - alias(libs.plugins.android.application) - alias(libs.plugins.kotlin.android) - alias(libs.plugins.flutter.gradle.plugin) + id("com.android.application") + id("kotlin-android") + id("dev.flutter.flutter-gradle-plugin") } android { diff --git a/sample/android/build.gradle.kts b/sample/android/build.gradle.kts index 90df827..89176ef 100644 --- a/sample/android/build.gradle.kts +++ b/sample/android/build.gradle.kts @@ -1,9 +1,17 @@ -rootProject.layout.buildDirectory.set(file("../build")) +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() +rootProject.layout.buildDirectory.value(newBuildDir) subprojects { - project.layout.buildDirectory.set(file("${rootProject.layout.buildDirectory.get()}/${project.name}")) + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) } - subprojects { project.evaluationDependsOn(":app") } diff --git a/sample/android/settings.gradle.kts b/sample/android/settings.gradle.kts index 10eaa47..d918456 100644 --- a/sample/android/settings.gradle.kts +++ b/sample/android/settings.gradle.kts @@ -3,7 +3,7 @@ pluginManagement { val properties = java.util.Properties() file("local.properties").inputStream().use { properties.load(it) } val flutterSdkPath = properties.getProperty("flutter.sdk") - checkNotNull(flutterSdkPath) { "flutter.sdk not set in local.properties" } + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } flutterSdkPath } @@ -20,7 +20,7 @@ dependencyResolutionManagement { repositories { google() mavenCentral() - maven { url = uri("https://central.sonatype.com/repository/maven-snapshots/") } + } versionCatalogs { @@ -31,9 +31,9 @@ dependencyResolutionManagement { } plugins { - id("com.android.application") version "8.10.1" apply false - id("org.jetbrains.kotlin.android") version "2.1.21" apply false id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.7.3" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false } include(":app") From abfed22f971036981c5cf58c1eb0c0cf3b19f289 Mon Sep 17 00:00:00 2001 From: Harun Wangereka Date: Tue, 10 Jun 2025 15:37:42 +0300 Subject: [PATCH 15/18] update AGP version --- android/gradle/libs.versions.toml | 2 +- android/gradle/wrapper/gradle-wrapper.properties | 2 +- sample/android/settings.gradle.kts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index 7b855ca..01704c5 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -android-gradle-plugin = "8.7.3" +android-gradle-plugin = "8.10.1" kotlin = "2.1.0" kotlin-immutable-collections = "0.4.0" ktlint-plugin = "12.3.0" diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 8fc91c8..7e7dbc6 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/sample/android/settings.gradle.kts b/sample/android/settings.gradle.kts index d918456..b6c8080 100644 --- a/sample/android/settings.gradle.kts +++ b/sample/android/settings.gradle.kts @@ -32,7 +32,7 @@ dependencyResolutionManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.7.3" apply false + id("com.android.application") version "8.10.1" apply false id("org.jetbrains.kotlin.android") version "2.1.0" apply false } From 03f2866111954829be54f5cbcd8329926ed8f636 Mon Sep 17 00:00:00 2001 From: Harun Wangereka Date: Tue, 10 Jun 2025 15:42:13 +0300 Subject: [PATCH 16/18] update kotlin version --- android/build.gradle.kts | 4 ++-- android/gradle/libs.versions.toml | 2 +- sample/android/settings.gradle.kts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/android/build.gradle.kts b/android/build.gradle.kts index fc56d9a..6b8369b 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -1,4 +1,4 @@ -val kotlinVersion = findProperty("kotlinVersion") as String? ?: "2.1.0" +val kotlinVersion = findProperty("kotlinVersion") as String? ?: "2.1.21" val kotlinCompilerExtension = findProperty("kotlinCompilerExtensionVersion") as String? ?: "1.5.14" extra.apply { @@ -7,7 +7,7 @@ extra.apply { } buildscript { - val kotlinVersion = rootProject.findProperty("kotlinVersion") as String? ?: "2.1.0" + val kotlinVersion = rootProject.findProperty("kotlinVersion") as String? ?: "2.1.21" dependencies { if (kotlinVersion.startsWith("2")) { diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index 01704c5..65a3bd7 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] android-gradle-plugin = "8.10.1" -kotlin = "2.1.0" +kotlin = "2.1.21" kotlin-immutable-collections = "0.4.0" ktlint-plugin = "12.3.0" mockk = "1.14.2" diff --git a/sample/android/settings.gradle.kts b/sample/android/settings.gradle.kts index b6c8080..7be483c 100644 --- a/sample/android/settings.gradle.kts +++ b/sample/android/settings.gradle.kts @@ -33,7 +33,7 @@ dependencyResolutionManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" id("com.android.application") version "8.10.1" apply false - id("org.jetbrains.kotlin.android") version "2.1.0" apply false + id("org.jetbrains.kotlin.android") version "2.1.21" apply false } include(":app") From 679dba071e1f3a48b57cd2990eaf87d46a445b47 Mon Sep 17 00:00:00 2001 From: Harun Wangereka Date: Tue, 10 Jun 2025 15:55:52 +0300 Subject: [PATCH 17/18] Change wording --- sample/test/widget_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample/test/widget_test.dart b/sample/test/widget_test.dart index a09e600..bc4107b 100644 --- a/sample/test/widget_test.dart +++ b/sample/test/widget_test.dart @@ -1,7 +1,7 @@ // This is a basic Flutter widget test. // // To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For sample, you can send tap and scroll +// utility in the flutter_test package. For example, you can send tap and scroll // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. From b9697b1b681239af516e0d9bec09936a22807984 Mon Sep 17 00:00:00 2001 From: Harun Wangereka Date: Tue, 10 Jun 2025 16:00:57 +0300 Subject: [PATCH 18/18] Update CHANGELOG.md Co-authored-by: prfectionist[bot] <187910262+prfectionist[bot]@users.noreply.github.com> --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad2bcdc..c6b980c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,8 @@ ## 11.0.2 -### Chnaged -* Renamed **exmaple** folder to **sample** and replaced all usages of example in the project. +### Changed +* Renamed **example** folder to **sample** and replaced all usages of example in the project. * Migrate all gradle files in the sample and SDK folders from Groovy to Kotlin. * Add a `libs.versions.toml` file to share dependencies between the sample project and the Android SDK. * Cleanup and minor code improvements on the gradlew files.