10
0

[MWA-5265] Meta Demo: Theming via xml testen

{Refactor UI to Jetpack Compose}
This commit is contained in:
andre 2025-11-17 13:41:20 +01:00
parent 761ff01110
commit 994ea9768d
3 changed files with 300 additions and 37 deletions

View File

@ -1,6 +1,7 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'org.jetbrains.kotlin.plugin.compose' version '2.1.0'
}
android {
@ -55,6 +56,7 @@ dependencies {
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.compose.material3:material3:1.4.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
@ -80,4 +82,17 @@ dependencies {
changing = true
}
def composeBom = platform('androidx.compose:compose-bom:2025.11.00')
implementation composeBom
androidTestImplementation composeBom
// Compose Core Dependencies
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.ui:ui-graphics'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.material3:material3'
implementation 'androidx.activity:activity-compose:1.9.3'
implementation 'androidx.compose.ui:ui-tooling-preview'
debugImplementation 'androidx.compose.ui:ui-tooling'
}

View File

@ -7,16 +7,20 @@ package de.webidsolutions.metaplugindemo
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.CheckBox
import android.widget.TextView
import androidx.activity.compose.setContent
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import de.webidsolutions.auto_ident_on_server_product_plugin.AutoIdentOnServerProductPlugin
import de.webidsolutions.eid_on_server_product_plugin.EIdOnServerProductPlugin
import de.webidsolutions.meta_plugin.EMetaPluginFailReason
import de.webidsolutions.meta_plugin.WebIdMetaPlugin
import de.webidsolutions.metaplugindemo.scenes.MetaPluginDemoScreen
import de.webidsolutions.metaplugindemo.scenes.ThemingChoice
import de.webidsolutions.metaplugindemo.tasks.EApiResult
import de.webidsolutions.metaplugindemo.tasks.MetaPluginVerifyTask
import de.webidsolutions.mobile_app.sdk.WebIdMobileAppSdkException
@ -56,32 +60,32 @@ private val chosenEnvironment: EWebIDEnv = EWebIDEnv.TEST
*/
internal class MainActivity : AppCompatActivity() {
private lateinit var eidOnServerPluginCb: CheckBox
private lateinit var payOnServerPluginCb: CheckBox
private lateinit var autoIdOnServerPluginCb: CheckBox
private lateinit var videoPluginCb: CheckBox
private lateinit var textLog: TextView
private lateinit var startButton: Button
private var logText by mutableStateOf("")
// private lateinit var coreSdk: IWebIdMobileAppSdk
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textLog = findViewById(R.id.log)
autoIdOnServerPluginCb = findViewById(R.id.cb_plugin_auto_id_on_server)
payOnServerPluginCb = findViewById(R.id.cb_plugin_pay_on_server)
eidOnServerPluginCb = findViewById(R.id.cb_plugin_eid_on_server)
videoPluginCb = findViewById(R.id.cb_plugin_video)
startButton = findViewById(R.id.startButton)
startButton.setOnClickListener {
clearLog()
writeLog(getString(R.string.starting))
createCoreSdk()
setContent {
MaterialTheme {
MetaPluginDemoScreen(
logText = logText,
onStartClicked = { useAutoIdent, usePayOnServer, useEidOnServer, useVideo, themingChoice ->
clearLog()
writeLog(getString(R.string.starting))
createCoreSdk(
useAutoIdent = useAutoIdent,
usePayOnServer = usePayOnServer,
useEidOnServer = useEidOnServer,
useVideo = useVideo,
themingChoice = themingChoice
)
}
)
}
}
}
/* CORE SDK */
@ -89,7 +93,13 @@ internal class MainActivity : AppCompatActivity() {
/**
* Creates the Core SDK from the existing credentials.
*/
private fun createCoreSdk() {
private fun createCoreSdk(
useAutoIdent: Boolean,
usePayOnServer: Boolean,
useEidOnServer: Boolean,
useVideo: Boolean,
themingChoice: ThemingChoice
) {
writeLog(getString(R.string.creating_core_sdk))
// should be provided to you -> currently just using demo credentials
@ -106,7 +116,12 @@ internal class MainActivity : AppCompatActivity() {
writeLog(getString(R.string.core_sdk_creation_successful))
validateActionId()
val selectProductPlugins = getSelectedPlugins()
val selectProductPlugins = getSelectedPlugins(
useAutoIdent = useAutoIdent,
usePayOnServer = usePayOnServer,
useEidOnServer = useEidOnServer,
useVideo = useVideo
)
val metaPlugin = WebIdMetaPlugin(
environment,
@ -142,13 +157,18 @@ internal class MainActivity : AppCompatActivity() {
this::onPluginResultCallback
)
private fun getSelectedPlugins(): ArrayList<IProductPluginWebId> {
private fun getSelectedPlugins(
useAutoIdent: Boolean,
usePayOnServer: Boolean,
useEidOnServer: Boolean,
useVideo: Boolean
): ArrayList<IProductPluginWebId> {
return ArrayList(
listOfNotNull(
if (autoIdOnServerPluginCb.isChecked) AutoIdentOnServerProductPlugin() else null,
if (payOnServerPluginCb.isChecked) PayOnServerProductPlugin() else null,
if (eidOnServerPluginCb.isChecked) EIdOnServerProductPlugin() else null,
if (videoPluginCb.isChecked) VideoIdentProductPlugin(config) else null,
if (useAutoIdent) AutoIdentOnServerProductPlugin() else null,
if (usePayOnServer) PayOnServerProductPlugin() else null,
if (useEidOnServer) EIdOnServerProductPlugin() else null,
if (useVideo) VideoIdentProductPlugin(config) else null,
)
)
}
@ -156,7 +176,6 @@ internal class MainActivity : AppCompatActivity() {
private fun metaPluginVerifyCallback(metaPlugin: WebIdMetaPlugin): (AsyncTaskResultGeneric<VerifyActionIdResult?, EApiResult>) -> Unit {
return { result ->
if (result.errorResult == EApiResult.SUCCESS) {
var verifyActionIdResult = result.result
try {
metaPlugin.startPlugin(
this,
@ -175,7 +194,6 @@ internal class MainActivity : AppCompatActivity() {
}
private fun onPluginResultCallback(activityResult: ActivityResult) {
var metaPluginActivityResult = activityResult
var result: String?
try {
// Get data and handle potential null case
@ -194,6 +212,7 @@ internal class MainActivity : AppCompatActivity() {
result += " $resultInfo"
// your code to handle the successful plugin execution
}
writeLog(result)
} else {
// failure case
if (failReason.specificResult != null) {
@ -203,30 +222,36 @@ internal class MainActivity : AppCompatActivity() {
if (specificResult is EMetaPluginFailReason) {
if (specificResult == EMetaPluginFailReason.EID_PENDING_AUTHADA) {
// handle EID_PENDING_AUTHADA as described in code documentation
writeLog("EID_PENDING_AUTHADA")
} else {
// handle all other EMetaPluginFailReason as described in code documentation
writeLog("MetaPluginFailReason: $specificResult")
}
} else {
// handle EVideoIdentProductPluginFailReasons
if (specificResult is EVideoIdentProductPluginFailReasons) {
if (specificResult == EVideoIdentProductPluginFailReasons.CALL_CENTER_CLOSED) {
// handle CALL_CENTER_CLOSED as described in code documentation
writeLog("CALL_CENTER_CLOSED")
} else {
// handle all other EVideoIdentProductPluginFailReasons errors as described in the code documentation
writeLog("VideoIdentFailReason: $specificResult")
}
}
}
} else {
if (failReason.genericResult == EProductPluginErrors.UNKNOWN) {
// handle UNKNOWN as described in code documentation
writeLog("Unknown Error")
} else {
// handle all other EProductPluginErrors errors as described in the code documentation
writeLog("Error: ${failReason.genericResult}")
}
}
}
} catch (e: WebIdPluginInterruptedException) {
// Handle interruption in your preferred way
writeLog(e.toString())
writeLog("Plugin interrupted: ${e.message}")
}
}
@ -234,18 +259,17 @@ internal class MainActivity : AppCompatActivity() {
/**
* Add an entry to the log.
*
* @param
*/
@SuppressLint("SetTextI18n")
private fun writeLog(entry: String) {
textLog.text = "${textLog.text} $entry\n"
logText += "$entry\n"
}
/**
* Resets the text log of this activity.
*/
private fun clearLog() {
textLog.text = ""
logText = ""
}
}

View File

@ -0,0 +1,224 @@
package de.webidsolutions.metaplugindemo.scenes
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Checkbox
import androidx.compose.material3.CheckboxDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import de.webidsolutions.metaplugindemo.R
enum class ThemingChoice {
CODE,
XML
}
@Composable
fun MetaPluginDemoScreen(
logText: String,
onStartClicked: (
useAutoIdent: Boolean,
usePayOnServer: Boolean,
useEidOnServer: Boolean,
useVideo: Boolean,
themingChoice: ThemingChoice
) -> Unit
) {
var useAutoIdent by remember { mutableStateOf(false) }
var usePayOnServer by remember { mutableStateOf(false) }
var useEidOnServer by remember { mutableStateOf(false) }
var useVideo by remember { mutableStateOf(false) }
var themingChoice by remember { mutableStateOf(ThemingChoice.CODE) }
Column(
modifier = Modifier
.fillMaxSize()
.padding(start = 10.dp, top = 10.dp, end = 10.dp)
.systemBarsPadding()
) {
Text(
text = stringResource(R.string.choose_plugins),
style = MaterialTheme.typography.bodyLarge
)
Spacer(modifier = Modifier.height(10.dp))
Column(modifier = Modifier.padding(start = 10.dp)) {
CheckboxWithLabel(
checked = useAutoIdent,
onCheckedChange = { useAutoIdent = it },
label = stringResource(R.string.autoid)
)
CheckboxWithLabel(
checked = usePayOnServer,
onCheckedChange = { usePayOnServer = it },
label = stringResource(R.string.accountid)
)
CheckboxWithLabel(
checked = useEidOnServer,
onCheckedChange = { useEidOnServer = it },
label = stringResource(R.string.eid)
)
CheckboxWithLabel(
checked = useVideo,
onCheckedChange = { useVideo = it },
label = stringResource(R.string.videoid)
)
}
Spacer(modifier = Modifier.height(10.dp))
Text(
text = stringResource(R.string.choose_theming),
style = MaterialTheme.typography.bodyLarge,
)
Spacer(modifier = Modifier.height(10.dp))
Column (
modifier = Modifier.padding(start = 10.dp),
) {
CheckboxWithLabel(
checked = themingChoice == ThemingChoice.CODE,
onCheckedChange = { themingChoice = ThemingChoice.CODE },
label = "Code-Theming"
)
CheckboxWithLabel(
checked = themingChoice == ThemingChoice.XML,
onCheckedChange = { themingChoice = ThemingChoice.XML },
label = "XML-Theming"
)
}
Spacer(modifier = Modifier.height(10.dp))
Text(
text = stringResource(R.string.log_headline),
style = MaterialTheme.typography.bodyLarge,
)
Spacer(modifier = Modifier.height(10.dp))
Surface(
modifier = Modifier
.weight(1f)
.fillMaxWidth()
.padding(horizontal = 10.dp),
color = MaterialTheme.colorScheme.surfaceVariant,
shape = MaterialTheme.shapes.small
) {
val scrollState = rememberScrollState()
LaunchedEffect(logText) {
scrollState.animateScrollTo(scrollState.maxValue)
}
Text(
text = logText.ifEmpty { stringResource(R.string.log_placeholder) },
modifier = Modifier
.fillMaxSize()
.verticalScroll(scrollState)
.padding(16.dp),
style = MaterialTheme.typography.bodyMedium
)
}
Spacer(modifier = Modifier.height(10.dp))
Button(
onClick = {
onStartClicked(
useAutoIdent,
usePayOnServer,
useEidOnServer,
useVideo,
themingChoice
)
},
modifier = Modifier
.fillMaxWidth()
.height(60.dp)
.padding(horizontal = 10.dp),
colors = ButtonDefaults.buttonColors(
containerColor = Color(0xFF05B1FB)
)
) {
Text(
text = stringResource(R.string.start_button),
color = Color.White
)
}
}
}
@Composable
private fun CheckboxWithLabel(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
label: String
) {
Row(
verticalAlignment = Alignment.CenterVertically,
) {
Checkbox(
checked = checked,
onCheckedChange = onCheckedChange,
colors = CheckboxDefaults.colors(
checkedColor = Color(0xFF05B1FB),
checkmarkColor = Color.White
)
)
Spacer(modifier = Modifier.width(2.dp))
Text(text = label)
}
}
@Preview(
name = "MetaPluginDemoScreen - Long Log",
showBackground = true,
showSystemUi = true
)
@Composable
private fun MetaPluginDemoScreenLongLogPreview() {
MaterialTheme {
MetaPluginDemoScreen(
logText = buildString {
repeat(20) { index ->
appendLine("Log entry ${index + 1}: Processing...")
}
},
onStartClicked = { _, _, _, _, _ -> }
)
}
}