Orchestration SDKs

Integrating the Journey module with Jetpack Compose

PingOne Advanced Identity Cloud PingAM Android

If your application uses Jetpack Compose, you can seamlessly integrate the Journey module by using a ViewModel to manage the UI state:

ViewModel

Using the Journey module with a JetPack Compose ViewModel
class AuthViewModel : ViewModel() {
    private val _state = MutableStateFlow<Node>(Empty)
    val state: StateFlow<Node> = _state

    private lateinit var journey: Journey // Initialize your Journey instance

    fun initializeJourney() {
        journey = Journey {
            // Configure your Journey instance here
            serverUrl = "https://openam-forgerock-sdks.forgeblocks.com/am"
            // ... other configurations
        }
    }

    fun startJourney(flowName: String = "sdkUsernamePasswordJourney") {
        viewModelScope.launch {
            val nextNode = journey.start(flowName)
            _state.update { nextNode }
        }
    }

    fun next(node: ContinueNode, input: Map<String, String> = emptyMap()) {
        viewModelScope.launch {
            val nextNode = node.next(input)
            _state.update { nextNode }
        }
    }
}

View (Composable)

Using the Journey module with a composable view
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.lifecycle.viewmodel.compose.viewModel

@Composable
fun AuthScreen() {
    val viewModel: AuthViewModel = viewModel()
    val authState by viewModel.state.collectAsState()

    // Initialize Journey when the composable is created
    LaunchedEffect(key1 = Unit) {
        viewModel.initializeJourney()
        viewModel.startJourney()
    }

    when (val node = authState) {
        is ContinueNode -> {
            // Render UI elements based on the callbacks in the node
            // Example: Display text fields for NameCallback and PasswordCallback
            val callbacks = node.callbacks
            // ... UI logic to collect user input and call viewModel.handleCallbacks()
        }
        is ErrorNode -> {
            // Display the error message
            Text(text = "Authentication Error: ${node.message}")
        }
        is FailureNode -> {
            // Display a generic error message
            Text(text = "An unexpected error occurred.")
            // Optionally log the errorCause
            Log.e("AuthScreen", "Authentication Failure", node.cause)
        }
        is SuccessNode -> {
            // Navigate to the main application screen
            Text(text = "Authentication Successful!")
            // ... Navigation logic
        }
    }
}