diff --git a/CHANGES.md b/CHANGES.md index 318e4b1..1dc2dde 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,9 @@ # Changelog +# 4.0.2 + +- Fix: passive site keys (hideDialog=true) broken for `compose-sdk` + # 4.0.1 - Feat: release of `compose-sdk` diff --git a/compose-sdk/build.gradle b/compose-sdk/build.gradle index b44db2d..8d327d2 100644 --- a/compose-sdk/build.gradle +++ b/compose-sdk/build.gradle @@ -20,11 +20,11 @@ android { // See https://developer.android.com/studio/publish/versioning // versionCode must be integer and be incremented by one for every new update // android system uses this to prevent downgrades - versionCode 40 + versionCode 41 // version number visible to the user // should follow semantic versioning (See https://semver.org) - versionName "4.0.1" + versionName "4.0.2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" diff --git a/compose-sdk/src/main/java/com/hcaptcha/sdk/HCaptchaCompose.kt b/compose-sdk/src/main/java/com/hcaptcha/sdk/HCaptchaCompose.kt index 6712c18..8c9238c 100644 --- a/compose-sdk/src/main/java/com/hcaptcha/sdk/HCaptchaCompose.kt +++ b/compose-sdk/src/main/java/com/hcaptcha/sdk/HCaptchaCompose.kt @@ -4,8 +4,10 @@ import android.app.Activity import android.os.Handler import android.os.Looper import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.size import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties @@ -13,9 +15,18 @@ import androidx.compose.ui.window.DialogProperties @Composable public fun HCaptchaCompose(config: HCaptchaConfig, onResult: (HCaptchaResponse) -> Unit) { val handler = Handler(Looper.getMainLooper()) + var helper: HCaptchaWebViewHelper? = null val verifier = object : IHCaptchaVerifier { override fun onLoaded() { onResult(HCaptchaResponse.Event(HCaptchaEvent.Loaded)) + if (config.hideDialog) { + helper?.let { + it.resetAndExecute() + } ?: run { + HCaptchaLog.w("HCaptchaWebViewHelper wasn't created, report but to developer") + onResult(HCaptchaResponse.Failure(HCaptchaError.INTERNAL_ERROR)) + } + } } override fun onOpen() { @@ -39,13 +50,16 @@ public fun HCaptchaCompose(config: HCaptchaConfig, onResult: (HCaptchaResponse) } } val internalConfig = HCaptchaInternalConfig(com.hcaptcha.sdk.HCaptchaHtml()) + HCaptchaLog.sDiagnosticsLogEnabled = config.diagnosticLog + + HCaptchaLog.d("HCaptchaCompose($config)") - Dialog(onDismissRequest = {}, properties = DialogProperties(usePlatformDefaultWidth = false)) { + if (config.hideDialog) { AndroidView( - modifier = Modifier.fillMaxSize(), + modifier = Modifier.size(0.dp), factory = { context -> HCaptchaWebView(context).apply { - HCaptchaWebViewHelper( + helper = HCaptchaWebViewHelper( handler, context, config, @@ -56,5 +70,26 @@ public fun HCaptchaCompose(config: HCaptchaConfig, onResult: (HCaptchaResponse) } } ) + } else { + Dialog( + onDismissRequest = {}, + properties = DialogProperties(usePlatformDefaultWidth = false) + ) { + AndroidView( + modifier = Modifier.fillMaxSize(), + factory = { context -> + HCaptchaWebView(context).apply { + helper = HCaptchaWebViewHelper( + handler, + context, + config, + internalConfig, + verifier, + this + ) + } + } + ) + } } } \ No newline at end of file diff --git a/example-compose-app/src/main/java/com/hcaptcha/example/compose/ComposeActivity.kt b/example-compose-app/src/main/java/com/hcaptcha/example/compose/ComposeActivity.kt index 95fb285..9d912dc 100644 --- a/example-compose-app/src/main/java/com/hcaptcha/example/compose/ComposeActivity.kt +++ b/example-compose-app/src/main/java/com/hcaptcha/example/compose/ComposeActivity.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Arrangement import androidx.compose.runtime.* import androidx.compose.material3.Button +import androidx.compose.material3.Checkbox import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -28,15 +29,16 @@ class ComposeActivity : ComponentActivity() { setContent { var hCaptchaStarted by remember { mutableStateOf(false) } var hCaptchaLoaded by remember { mutableStateOf(false) } + var hideDialog by remember { mutableStateOf(false) } var text by remember { mutableStateOf("") } Column( modifier = Modifier.fillMaxSize().padding(16.dp), verticalArrangement = Arrangement.Bottom ) { - // Multiline Text TextField( value = text, + placeholder = { Text("Verification result will be here...") }, onValueChange = { newText -> text = newText }, modifier = Modifier .fillMaxWidth() @@ -44,15 +46,32 @@ class ComposeActivity : ComponentActivity() { .background(Color.Gray) ) + Spacer(modifier = Modifier.weight(1f)) + + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Checkbox( + checked = hideDialog, + onCheckedChange = { isChecked -> + hideDialog = isChecked + } + ) + + Text( + text = "Hide Dialog (Passive Site Key)", + ) + } + Button( onClick = { hCaptchaStarted = !hCaptchaStarted }, modifier = Modifier .fillMaxWidth() - .padding(top = 16.dp) + .padding(vertical = 16.dp) ) { - Text(text = "Toggle WebView") + Text(text = "Verify with HCaptcha") } if (hCaptchaStarted && !hCaptchaLoaded) { @@ -68,11 +87,12 @@ class ComposeActivity : ComponentActivity() { } } - // WebView Dialog if (hCaptchaStarted) { HCaptchaCompose(HCaptchaConfig .builder() .siteKey("10000000-ffff-ffff-ffff-000000000001") + .hideDialog(hideDialog) + .diagnosticLog(true) .build()) { result -> when (result) { is HCaptchaResponse.Success -> { @@ -89,7 +109,7 @@ class ComposeActivity : ComponentActivity() { } is HCaptchaResponse.Event -> { if (result.event == HCaptchaEvent.Opened) { - hCaptchaLoaded = true; + hCaptchaLoaded = true } println("Event: ${result.event}") } diff --git a/sdk/build.gradle b/sdk/build.gradle index 7919942..bb045aa 100644 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -28,11 +28,11 @@ android { // See https://developer.android.com/studio/publish/versioning // versionCode must be integer and be incremented by one for every new update // android system uses this to prevent downgrades - versionCode 40 + versionCode 41 // version number visible to the user // should follow semantic versioning (See https://semver.org) - versionName "4.0.1" + versionName "4.0.2" buildConfigField 'String', 'VERSION_NAME', "\"${defaultConfig.versionName}_${defaultConfig.versionCode}\"" diff --git a/test/src/androidTest/java/com/hcaptcha/sdk/compose/HCaptchaComposeTest.kt b/test/src/androidTest/java/com/hcaptcha/sdk/compose/HCaptchaComposeTest.kt index 5f44de9..6e48f86 100644 --- a/test/src/androidTest/java/com/hcaptcha/sdk/compose/HCaptchaComposeTest.kt +++ b/test/src/androidTest/java/com/hcaptcha/sdk/compose/HCaptchaComposeTest.kt @@ -16,6 +16,7 @@ import com.hcaptcha.sdk.HCaptchaCompose import com.hcaptcha.sdk.HCaptchaConfig import com.hcaptcha.sdk.HCaptchaError import com.hcaptcha.sdk.HCaptchaResponse +import com.hcaptcha.sdk.HCaptchaSize import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import org.junit.Rule @@ -25,13 +26,18 @@ import java.util.concurrent.TimeUnit @RunWith(AndroidJUnit4::class) class HCaptchaComposeTest { + companion object { + const val SITE_KEY = "10000000-ffff-ffff-ffff-000000000001" + const val TEST_TOKEN = "10000000-aaaa-bbbb-cccc-000000000001" + } + private val resultContentDescription = "HCaptchaResultString" private val timeout = TimeUnit.SECONDS.toMillis(4) @get:Rule val composeTestRule = createComposeRule() - fun setContent(token: String = "10000000-ffff-ffff-ffff-000000000001") { + fun setContent(siteKey: String = SITE_KEY, passiveSiteKey: Boolean = false) { composeTestRule.setContent { var text by remember { mutableStateOf("") } Column { @@ -39,8 +45,10 @@ class HCaptchaComposeTest { HCaptchaCompose(HCaptchaConfig .builder() - .siteKey(token) + .siteKey(siteKey) .diagnosticLog(true) + .size(HCaptchaSize.INVISIBLE) + .hideDialog(passiveSiteKey) .build()) { result -> when (result) { is HCaptchaResponse.Success -> { @@ -63,7 +71,7 @@ class HCaptchaComposeTest { runBlocking { delay(timeout) } composeTestRule.onNodeWithContentDescription(resultContentDescription) - .assertTextEquals("10000000-aaaa-bbbb-cccc-000000000001") + .assertTextEquals(TEST_TOKEN) } @Test @@ -75,4 +83,14 @@ class HCaptchaComposeTest { composeTestRule.onNodeWithContentDescription(resultContentDescription) .assertTextContains(HCaptchaError.ERROR.name) } + + @Test + fun passiveSiteKey() { + setContent(SITE_KEY, true) + + runBlocking { delay(timeout) } + + composeTestRule.onNodeWithContentDescription(resultContentDescription) + .assertTextEquals(TEST_TOKEN) + } } \ No newline at end of file