Skip to main content
Logo
Explore APIsContact Us
  • Home
  1. Resources
  2. Virtual Stadium
  3. Profile Component

Profile Component

The Profile component displays user information, statistics, and betting activity within the Virtual Stadium community. It shows a user's shared bets, copy count, and engagement metrics, and is typically accessed through the Chat component's user interactions.

#Overview

The Profile component provides a detailed view of a user's activity in the Virtual Stadium community:

  1. Display the Profile component when users click on profiles in Chat
  2. Configure with the selected user ID and UI settings
  3. Show user statistics, bet history, and engagement metrics
  4. Handle profile dismissal and navigation
  5. Customize appearance to match your Chat component theme

This guide will walk you through each step with code examples and best practices.

info

Prerequisites

  • The SDK must be initialized with VirtualStadiumUISDK.init()

#Basic Integration

#Jetpack Compose

The Profile component is independent from the Chat component. It can be displayed by only providing jwtToken and userId parameters.

Required Parameters:

jwtToken String required

JWT token required to authenticate and initialize the UI SDK. This should be the same token used for the Chat component.

userId String required

The unique identifier of the user whose profile to display. This is typically provided by the Chat component's onProfileClicked callback.

Optional Parameters:

modifier Modifier optional

Compose modifier for layout customization. Use this to control size, padding, and other layout properties. Default: Modifier

analyticsProvider AnalyticsProvider optional

Provider for analytics event tracking. Used to log user interactions and profile view events. Should match the Chat component's analytics provider for consistent tracking. Default: AnalyticsProvider()

uiSettings UISettings optional

Customization settings for theming, fonts, and icons. Should match the Chat component settings for visual consistency across your application. Default: defaultUISettings()

onClosedClicked (() -> Unit)? optional

Callback invoked when the user clicks the close button on the profile screen. Use this to handle navigation back to the chat or dismiss the profile overlay. If null, the close button will not be shown.

onCopyToBetSlip ((BetPayload) -> Unit)? optional

Callback invoked when the user copies a shared bet from the profile to their bet slip. Receives the BetPayload containing the bet details. Use this to integrate with your betting system.

onTagClicked ((Tag) -> Unit)? optional

Callback invoked when the user clicks on a tag within bet shares on the profile. Receives the Tag object that was clicked. Use this to handle tag filtering or navigation.

info

The Profile component is designed to overlay the Chat component. Use state management to toggle its visibility based on user interactions.

MainActivity.kt:

kotlin
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.core.view.WindowCompat
import ag.sportradar.virtualstadium.uisdk.compose.Chat
import ag.sportradar.virtualstadium.uisdk.compose.Profile
import ag.sportradar.virtualstadium.uisdk.LanguageCode

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        WindowCompat.setDecorFitsSystemWindows(window, false)

        setContent {
            ChatScreen()
        }
    }
}

@Composable
fun ChatScreen() {
    var showProfile by remember { mutableStateOf(false) }
    var selectedUserId by remember { mutableStateOf("") }

    Box(Modifier.fillMaxSize()) {
        // Chat component
        /**
         * TODO(developer): Replace <your-jwt-token> with your actual JWT token
         * and <your-channel-id> with your actual channel ID before running this code.
         */
        Chat(
            jwtToken = "<your-jwt-token>",
            channelId = "<your-channel-id>",
            languageCode = LanguageCode.EN,
            modifier = Modifier.fillMaxSize(),
            onProfileClicked = { userId ->
                selectedUserId = userId
                showProfile = true
            }
        )

        // Profile overlay
        if (showProfile) {
            Profile(
                modifier = Modifier.fillMaxSize(),
                jwtToken = "<your-jwt-token>",
                userId = selectedUserId,
                onClosedClicked = {
                    showProfile = false
                    selectedUserId = ""
                }
            )
        }
    }
}

#Android Views

Add the Profile component using traditional Android Views with XML layout. The component is initialized programmatically when a user profile is selected.

Required Parameters:

jwtToken String required

JWT token required to authenticate and initialize the UI SDK.

userId String required

The unique identifier of the user whose profile to display.

Optional Parameters:

analyticsProvider AnalyticsProvider optional

Provider for analytics event tracking.

uiSettings UISettings optional

Customization settings for theming, fonts, and icons. Should match the Chat component settings.

onClosedClicked (() -> Unit)? optional

Callback invoked when the user closes the profile screen.

onCopyToBetSlip ((BetPayload) -> Unit)? optional

Callback invoked when the user copies a bet from the profile.

onTagClicked ((Tag) -> Unit)? optional

Callback invoked when the user clicks on a tag.

activity_main.xml:

xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ag.sportradar.virtualstadium.uisdk.views.VirtualStadiumChatView
        android:id="@+id/chat_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <ag.sportradar.virtualstadium.uisdk.views.VirtualStadiumProfileView
        android:id="@+id/profile_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone" />

</FrameLayout>

#Profile Content

The Profile component displays the following information:

#User Header

  • Display Name - The user's name in the community
  • Avatar
  • Close Button - Dismiss the profile view

#Statistics Section

MetricDescription
Bets SharedTotal number of bet slips the user has shared with the community
Bets CopiedNumber of times other users have copied this user's bets

#Bet History

  • Chronological List - All bet slips shared by the user
  • Bet Details - Each bet slip shows:
    • Bet type (Single, Multi, Bet Builder, etc.)
    • Markets and outcomes
    • Odds and potential payout
    • Timestamp
  • Copy Action - Other users can copy bets directly from the profile

#Styling and Theming

For a cohesive user experience, use the same uiSettings for both Chat and Profile components. This ensures consistent colors, fonts, and icons throughout your application.

#Shared Theme Configuration

Create a single UISettings instance and reuse it across both components. This maintains visual consistency and simplifies theme management.

Best Practice:

  • Define your theme settings once
  • Share across Chat and Profile components
  • Update in a single location when styling changes
warning

Using different uiSettings for Chat and Profile will result in an inconsistent user experience. Always share the same theme configuration.

Shared Theme Example:

kotlin
import ag.sportradar.virtualstadium.uisdk.compose.*
import androidx.compose.ui.graphics.Color

val customTheme = defaultThemeSettings(
    colorScheme = myCustomColorScheme(),
    loadingIndicatorColor = Color(0xFF1976D2),
    // ... other theme settings
)

val sharedUISettings = defaultUISettings(
    themeSettings = customTheme,
    fontFamily = myCustomFont(),
    iconsSettings = myCustomIcons()
)

@Composable
fun ChatScreen() {
    var showProfile by remember { mutableStateOf(false) }
    var selectedUserId by remember { mutableStateOf("") }

    Box(Modifier.fillMaxSize()) {
        Chat(
            jwtToken = "<jwt-token>",
            channelId = "<channel-id>",
            languageCode = LanguageCode.EN,
            uiSettings = sharedUISettings,  // Shared settings
            onProfileClicked = { userId ->
                selectedUserId = userId
                showProfile = true
            }
        )

        if (showProfile) {
            Profile(
                jwtToken = "<jwt-token>",
                userId = selectedUserId,
                uiSettings = sharedUISettings,  // Same settings
                onClosedClicked = {
                    showProfile = false
                }
            )
        }
    }
}

#Advanced Implementation

#Navigation Component Integration

Integrate with Jetpack Navigation for proper back stack management and deep linking support. This approach provides better control over navigation and supports the Android back button.

Benefits:

  • Proper back stack management
  • Support for deep linking to profiles
  • Better state preservation
  • System back button handling

Navigation Integration:

kotlin
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.NavType
import androidx.navigation.navArgument

@Composable
fun ChatNavHost() {
    val navController = rememberNavController()

    NavHost(
        navController = navController,
        startDestination = "chat"
    ) {
        composable("chat") {
            Chat(
                jwtToken = "<jwt-token>",
                channelId = "<channel-id>",
                languageCode = LanguageCode.EN,
                modifier = Modifier.fillMaxSize(),
                onProfileClicked = { userId ->
                    navController.navigate("profile/$userId")
                }
            )
        }

        composable(
            route = "profile/{userId}",
            arguments = listOf(
                navArgument("userId") { 
                    type = NavType.StringType 
                }
            )
        ) { backStackEntry ->
            val userId = backStackEntry.arguments?.getString("userId") ?: ""
            
            Profile(
                jwtToken = "<jwt-token>",
                userId = userId,
                modifier = Modifier.fillMaxSize(),
                onClosedClicked = {
                    navController.popBackStack()
                }
            )
        }
    }
}

#Bottom Sheet Integration

Display the profile in a modal bottom sheet for a more native mobile experience. This pattern is ideal when you want to maintain visibility of the chat in the background.

Use Cases:

  • Quick profile previews
  • Maintaining chat context
  • Mobile-first design patterns
  • Non-intrusive profile viewing

Bottom Sheet Profile:

kotlin
import androidx.compose.material3.*

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ChatWithBottomSheetProfile() {
    val sheetState = rememberModalBottomSheetState()
    var showProfile by remember { mutableStateOf(false) }
    var selectedUserId by remember { mutableStateOf("") }

    Box(Modifier.fillMaxSize()) {
        Chat(
            jwtToken = "<jwt-token>",
            channelId = "<channel-id>",
            languageCode = LanguageCode.EN,
            modifier = Modifier.fillMaxSize(),
            onProfileClicked = { userId ->
                selectedUserId = userId
                showProfile = true
            }
        )

        if (showProfile) {
            ModalBottomSheet(
                onDismissRequest = { showProfile = false },
                sheetState = sheetState
            ) {
                Profile(
                    jwtToken = "<jwt-token>",
                    userId = selectedUserId,
                    modifier = Modifier
                        .fillMaxWidth()
                        .fillMaxHeight(0.9f),
                    onClosedClicked = {
                        showProfile = false
                    }
                )
            }
        }
    }
}

#Complete Example

Here's a full implementation combining all best practices:

Includes:

  • ViewModel for state management
  • Shared UI settings for consistency
  • Animated transitions
  • User ID validation
  • Proper callbacks for bet sharing
  • Window insets handling

This example demonstrates production-ready code with proper architecture and error handling.

CompleteProfileExample.kt:

kotlin
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.*
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.core.view.WindowCompat
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewmodel.compose.viewModel
import ag.sportradar.virtualstadium.uisdk.compose.*
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

class ChatViewModel : ViewModel() {
    private val _showProfile = MutableStateFlow(false)
    val showProfile: StateFlow<Boolean> = _showProfile

    private val _selectedUserId = MutableStateFlow("")
    val selectedUserId: StateFlow<String> = _selectedUserId

    fun showProfile(userId: String) {
        if (userId.isNotBlank()) {
            _selectedUserId.value = userId
            _showProfile.value = true
        }
    }

    fun hideProfile() {
        _showProfile.value = false
        _selectedUserId.value = ""
    }
}

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Enable edge-to-edge display
        WindowCompat.setDecorFitsSystemWindows(window, false)

        setContent {
            ChatScreen()
        }
    }
}

@Composable
fun ChatScreen(viewModel: ChatViewModel = viewModel()) {
    val showProfile by viewModel.showProfile.collectAsState()
    val selectedUserId by viewModel.selectedUserId.collectAsState()

    // Shared UI settings for consistency
    val sharedUISettings = remember {
        defaultUISettings(
            themeSettings = defaultThemeSettings(
                colorScheme = myCustomColorScheme()
            ),
            fontFamily = myCustomFont(),
            iconsSettings = myCustomIcons()
        )
    }

    Box(Modifier.fillMaxSize()) {
        // Main chat component
        /**
         * TODO(developer): Replace <your-jwt-token> with your actual JWT token
         * and <your-channel-id> with your actual channel ID before running this code.
         */
        Chat(
            jwtToken = "<your-jwt-token>",
            channelId = "<your-channel-id>",
            languageCode = LanguageCode.EN,
            modifier = Modifier.fillMaxSize(),
            uiSettings = sharedUISettings,
            
            // Bet sharing callbacks
            betSlipListProvider = { getBetSlips() },
            onCopyToBetSlipClicked = { bet -> copyBet(bet) },
            
            // Profile integration with validation
            onProfileClicked = { userId ->
                viewModel.showProfile(userId)
            }
        )

        // Animated profile overlay
        AnimatedVisibility(
            visible = showProfile,
            enter = slideInHorizontally(
                initialOffsetX = { it },
                animationSpec = tween(300)
            ) + fadeIn(),
            exit = slideOutHorizontally(
                targetOffsetX = { it },
                animationSpec = tween(300)
            ) + fadeOut()
        ) {
            Profile(
                jwtToken = "<your-jwt-token>",
                userId = selectedUserId,
                modifier = Modifier.fillMaxSize(),
                uiSettings = sharedUISettings,
                onClosedClicked = {
                    viewModel.hideProfile()
                },
                onCopyToBetSlip = { bet -> copyBet(bet) },
                onTagClicked = { tag -> handleTagClick(tag) }
            )
        }
    }
}

Last updated about 1 month ago
Is this site helpful?
Virtual Stadium, Moderation, Engagement Tools
Chat ComponentCentral Hub Component
On this page
  • Overview
  • Basic Integration
  • Jetpack Compose
  • Android Views
  • Profile Content
  • User Header
  • Statistics Section
  • Bet History
  • Styling and Theming
  • Shared Theme Configuration
  • Advanced Implementation
  • Navigation Component Integration
  • Bottom Sheet Integration
  • Complete Example