### Start Tours using LocalTourController Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Obtain the `TourController` instance from `LocalTourController.current` and call `startTour` with the desired tour flow ID to initiate a tour. ```kotlin @Composable fun StartTourButtons() { val tourController = LocalTourController.current Row { Button( onClick = { tourController.startTour(WELCOME_TOUR) } ) { Text("Start Welcome Tour") } Button( onClick = { tourController.startTour(FEATURE_TOUR) } ) { Text("Start Feature Tour") } } } ``` -------------------------------- ### Basic TourCompose Setup Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Set up TourCompose in your Composable screen by creating a tour controller and wrapping your UI with TourComposeWrapper. Access the controller via LocalTourController. ```kotlin @Composable fun MainScreen() { // Create your tour controller val tourController = remember { MyTourController() } TourComposeWrapper( tourController = tourController ) { // Access the tour controller anywhere in the tree val controller = LocalTourController.current val currentStep by controller.currentStep.collectAsState(initial = null) // Your main UI content MyContent() // Tour overlay - shows when tour is active TourCompose( componentRectArea = currentStep?.componentRect, bubbleContentSettings = currentStep?.bubbleContentSettings ) } } ``` -------------------------------- ### Create Onboarding Tour Flow Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Defines an onboarding tour with multiple steps using TourCompose. This example shows how to set up welcome, feature discovery, and completion steps. ```kotlin import com.example.tourcompose.core.TourComposeController import com.example.tourcompose.core.TourComposeStep import com.example.tourcompose.core.settings.bubbleContentBasicSettings class OnboardingTourController : TourComposeController() { init { addTour( flowId = "onboarding", steps = listOf( // Welcome step TourComposeStep( id = "welcome", bubbleContentSettings = bubbleContentBasicSettings( title = "Welcome to MyApp! 🎉", description = "Let's get you started with a quick tour of the main features", primaryButtonText = "Let's Go!", onPrimaryClick = { nextStep() }, onDismiss = { stopTour() } ) ), // Feature discovery TourComposeStep( id = "search", bubbleContentSettings = bubbleContentBasicSettings( title = "Search Anything 🔍", description = "Use this search bar to find content quickly and easily", primaryButtonText = "Next", secondaryButtonText = "Skip", onPrimaryClick = { nextStep() }, onSecondaryClick = { stopTour() }, onDismiss = { stopTour() } ) ), // Call to action TourComposeStep( id = "get_started", bubbleContentSettings = bubbleContentBasicSettings( title = "You're All Set! ✅", description = "Start exploring and don't hesitate to check out the help section if you need assistance", primaryButtonText = "Start Exploring", onPrimaryClick = { stopTour() // Navigate to main content or show success message }, onDismiss = { stopTour() } ) ) ) ) } } ``` -------------------------------- ### Introduce New Feature with Tour Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Defines a tour to introduce a new feature using TourCompose. This example demonstrates a single step tour with primary and secondary action buttons. ```kotlin import com.example.tourcompose.core.TourComposeController import com.example.tourcompose.core.TourComposeStep import com.example.tourcompose.core.settings.bubbleContentBasicSettings class FeatureIntroController : TourComposeController() { init { addTour( flowId = "new_feature", steps = listOf( TourComposeStep( id = "new_button", bubbleContentSettings = bubbleContentBasicSettings( title = "New Feature Alert! 🆕", description = "We've added a new collaboration feature. Tap here to invite team members!", primaryButtonText = "Try It", secondaryButtonText = "Later", onPrimaryClick = { stopTour() // Open feature or navigate }, onSecondaryClick = { stopTour() }, onDismiss = { stopTour() } ) ) ) ) } } ``` -------------------------------- ### TourComposeWrapper Setup Source: https://context7.com/antoniohreyes/tourcompose/llms.txt Use TourComposeWrapper to wrap your UI content. It provides the TourComposeController and TourComposeScope, enabling the use of .tourStepIndex() and LocalTourController.current within its children. ```kotlin @Composable fun MyScreen() { val tourController = remember { MyTourController() } TourComposeWrapper(tourController = tourController) { // All child composables within this scope can use .tourStepIndex() // and access LocalTourController.current MyScreenContent() } } ``` -------------------------------- ### TourComposeController Abstract Class Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Base class for managing tour logic and state. Provides methods for starting, stopping, and navigating tours, as well as accessing current state. ```kotlin abstract class TourComposeController { fun startTour(flowId: String) fun stopTour() fun nextStep() fun previousStep() fun addTour(flowId: String, steps: List) val currentStep: StateFlow val isActive: Boolean } ``` -------------------------------- ### Implement Custom Bubble UI with `BubbleContentSettings` Source: https://context7.com/antoniohreyes/tourcompose/llms.txt Implement the `BubbleContentSettings` interface to create fully custom bubble UIs. The `DrawContent` composable function allows rendering any arbitrary Compose content. This example shows a progress indicator and navigation buttons. ```kotlin @Immutable class ProgressBubbleContent( override val modifier: Modifier = Modifier, override val title: String, override val description: String, val currentStep: Int, val totalSteps: Int, override val onDismiss: () -> Unit, val onNext: () -> Unit, val onPrevious: () -> Unit ) : BubbleContentSettings { @Composable override fun DrawContent(modifier: Modifier) { Card( modifier = modifier, colors = CardDefaults.cardColors( containerColor = MaterialTheme.colorScheme.primaryContainer ) ) { Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp)) { // Title row with close button Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { Text(title, style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold) IconButton(onClick = onDismiss) { Icon(Icons.Default.Close, contentDescription = "Close") } } // Progress Column { Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) { Text("Step $currentStep of $totalSteps", style = MaterialTheme.typography.labelMedium) } LinearProgressIndicator( progress = { currentStep.toFloat() / totalSteps }, modifier = Modifier.fillMaxWidth().clip(RoundedCornerShape(4.dp)) ) } Text(description, style = MaterialTheme.typography.bodyMedium) // Navigation buttons Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.End)) { if (currentStep > 1) { OutlinedButton(onClick = onPrevious) { Text("Previous") } } Button(onClick = if (currentStep < totalSteps) onNext else onDismiss) { Text(if (currentStep < totalSteps) "Next" else "Finish") } } } } } } // Usage in controller: TourComposeStep( id = "step_1", bubbleContentSettings = ProgressBubbleContent( title = "Getting Started", description = "Welcome to the app! This tour has 3 steps.", currentStep = 1, totalSteps = 3, onNext = { nextStep() }, onPrevious = {}, onDismiss = { stopTour() } ) ) ``` -------------------------------- ### Implement TourComposeController for App Tours Source: https://context7.com/antoniohreyes/tourcompose/llms.txt Subclass TourComposeController to define named tour flows and their steps. Override lifecycle hooks for analytics or persistence. This example shows how to add onboarding and feature tours. ```kotlin class AppTourController : TourComposeController() { companion object { const val ONBOARDING_FLOW = "onboarding" const val FEATURE_FLOW = "new_feature" } init { addTour(flowId = ONBOARDING_FLOW, steps = buildOnboardingSteps()) addTour(flowId = FEATURE_FLOW, steps = buildFeatureSteps()) } // Override lifecycle hooks for analytics or persistence override fun onTourStart(flowId: String) { super.onTourStart(flowId) analytics.track("tour_started", mapOf("flow" to flowId)) } override fun onTourEnd(flowId: String) { super.onTourEnd(flowId) prefs.markTourSeen(flowId) } private fun buildOnboardingSteps() = listOf( TourComposeStep( id = "welcome", bubbleContentSettings = bubbleContentBasicSettings( title = "Welcome! 👋", description = "Let's show you around the app.", primaryButtonText = "Let's Go", onPrimaryClick = { nextStep() }, onDismiss = { stopTour() } ) ), TourComposeStep( id = "search_bar", bubbleContentSettings = bubbleContentBasicSettings( title = "Search", description = "Find anything quickly using this search bar.", primaryButtonText = "Next", secondaryButtonText = "Back", onPrimaryClick = { nextStep() }, onSecondaryClick = { previousStep() }, onDismiss = { stopTour() } ) ), TourComposeStep( id = "profile", bubbleContentSettings = bubbleContentBasicSettings( title = "Your Profile", description = "Manage your account settings here.", primaryButtonText = "Done", secondaryButtonText = "Back", onPrimaryClick = { stopTour() }, onSecondaryClick = { previousStep() }, onDismiss = { stopTour() } ) ) ) private fun buildFeatureSteps() = listOf( TourComposeStep( id = "new_button", bubbleContentSettings = bubbleContentBasicSettings( title = "New Feature! 🆕", description = "Tap here to invite collaborators to your workspace.", primaryButtonText = "Try It", onPrimaryClick = { stopTour() }, onDismiss = { stopTour() } ) ) ) } ``` -------------------------------- ### Conditionally Start Tours with LaunchedEffect Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Use LaunchedEffect to trigger tours based on user state like first-time visits or new features. Ensure the necessary state variables are managed. ```kotlin @Composable fun ConditionalTourExample() { val tourController = LocalTourController.current val isFirstTime = remember { /* check if first time user */ true } val hasNewFeatures = remember { /* check for new features */ false } LaunchedEffect(isFirstTime, hasNewFeatures) { when { isFirstTime -> tourController.startTour("onboarding") hasNewFeatures -> tourController.startTour("new_features") } } } ``` -------------------------------- ### Get Default Color Schemes Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Provides default color schemes that adapt to the Material Theme. Use these composable functions to easily apply predefined color palettes to your tour elements. ```kotlin @Composable fun defaultSpotlightColors(): SpotlightColors ``` ```kotlin @Composable fun defaultDialogBubbleColors(): DialogBubbleColors ``` ```kotlin @Composable fun defaultBubbleContentColors(): BubbleContentColors ``` -------------------------------- ### Add a Help Tour to TourComposeController Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Extend TourComposeController to add a tour with specific steps and content. Use this for creating custom help or tips flows. ```kotlin class HelpTourController : TourComposeController() { init { addTour( flowId = "quick_tips", steps = listOf( TourComposeStep( id = "tip_shortcuts", bubbleContentSettings = bubbleContentBasicSettings( title = "💡 Pro Tip", description = "Long press on items for quick actions and shortcuts", primaryButtonText = "Good to Know", onPrimaryClick = { stopTour() }, onDismiss = { stopTour() } ) ) ) ) } } ``` -------------------------------- ### Create a Tour Controller Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Define a custom TourController to manage and add tours. This involves creating tour steps with specific content and actions. ```kotlin class MyTourController : TourComposeController() { companion object { const val WELCOME_TOUR = "welcome_tour" const val FEATURE_TOUR = "feature_tour" } init { // Add your tours addTour( flowId = WELCOME_TOUR, steps = createWelcomeTourSteps() ) addTour( flowId = FEATURE_TOUR, steps = createFeatureTourSteps() ) } private fun createWelcomeTourSteps() = listOf( TourComposeStep( id = "welcome_step", bubbleContentSettings = bubbleContentBasicSettings( title = "Welcome to TourCompose! 👋", description = "Let's take a quick tour of the main features", primaryButtonText = "Start Tour", onPrimaryClick = { nextStep() }, onDismiss = { stopTour() } ) ), TourComposeStep( id = "button_step", bubbleContentSettings = bubbleContentBasicSettings( title = "Action Button", description = "This button performs the main action", primaryButtonText = "Next", secondaryButtonText = "Previous", onPrimaryClick = { nextStep() }, onSecondaryClick = { previousStep() }, onDismiss = { stopTour() } ) ), TourComposeStep( id = "menu_step", bubbleContentSettings = bubbleContentBasicSettings( title = "Menu Options", description = "Access additional options from here", primaryButtonText = "Finish", secondaryButtonText = "Back", onPrimaryClick = { stopTour() }, onSecondaryClick = { previousStep() }, onDismiss = { stopTour() } ) ) ) } ``` -------------------------------- ### Create Basic Bubble Content with bubbleContentBasicSettings Source: https://context7.com/antoniohreyes/tourcompose/llms.txt The `bubbleContentBasicSettings` helper function creates a standard `BubbleContentSettings` object. It includes options for title, description, primary/secondary buttons, a dismiss button, and custom colors. Use this for the core module when not using Material3. ```kotlin val step = TourComposeStep( id = "settings_step", bubbleContentSettings = bubbleContentBasicSettings( title = "Settings ⚙️", description = "Customize your experience: notifications, themes, and privacy options.", primaryButtonText = "Next", secondaryButtonText = "Skip", colors = defaultBubbleContentColors().copy( titleTextColor = Color(0xFF6200EE), descriptionTextColor = Color(0xFF3700B3), iconTintColor = Color(0xFF03DAC6), dividerColor = Color(0xFFBB86FC) ), onPrimaryClick = { nextStep() }, onSecondaryClick = { stopTour() }, onDismiss = { stopTour() } ) ) ``` -------------------------------- ### Advanced TourCompose Color Theming Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Create custom spotlight, bubble, and content colors using `DefaultSpotlightColors`, `DefaultDialogBubbleColors`, and `defaultBubbleContentColors`. Apply these to the `TourCompose` properties. ```kotlin // Create custom spotlight colors val customSpotlightColors = DefaultSpotlightColors( overlayBackgroundColor = Color(0xFF6200EE).copy(alpha = 0.7f), overlayBorderColor = Color(0xFF03DAC6) ) // Create custom bubble colors val customBubbleColors = DefaultDialogBubbleColors( backgroundColor = Color(0xFF121212) ) // Create custom content colors val customContentColors = defaultBubbleContentColors().copy( titleTextColor = Color.White, descriptionTextColor = Color.White.copy(alpha = 0.8f), iconTintColor = Color(0xFF03DAC6), dividerColor = Color.White.copy(alpha = 0.2f) ) // Apply all customizations TourCompose( componentRectArea = currentStep?.componentRect, bubbleContentSettings = currentStep?.bubbleContentSettings, tourComposeProperties = TourComposeProperties( spotlightColors = customSpotlightColors, dialogBubbleColors = customBubbleColors ) ) ``` -------------------------------- ### Configure TourCompose Spotlight and Bubble Colors Source: https://context7.com/antoniohreyes/tourcompose/llms.txt Use TourComposeProperties for manual color configuration in the core module. For Material3 integration, use TourComposeMaterial3Properties to override specific tokens while maintaining theme alignment. ```kotlin TourCompose( componentRectArea = step.componentRect, bubbleContentSettings = step.bubbleContentSettings, tourComposeProperties = TourComposeProperties( spotlightColors = DefaultSpotlightColors( overlayBackgroundColor = Color(0xFF1A237E).copy(alpha = 0.85f), // deep navy dim overlayBorderColor = Color(0xFF40C4FF) // accent border ), dialogBubbleColors = DefaultDialogBubbleColors( backgroundColor = Color(0xFF0D1B2A) // dark bubble background ) ) ) ``` ```kotlin TourComposeMaterial3( componentRectArea = step.componentRect, bubbleContentSettings = step.bubbleContentSettings, tourComposeProperties = TourComposeMaterial3Properties( spotlightColors = DefaultSpotlightColors( overlayBackgroundColor = MaterialTheme.colorScheme.scrim.copy(alpha = 0.9f), overlayBorderColor = MaterialTheme.colorScheme.tertiary // use tertiary instead of primary ), dialogBubbleColors = DefaultDialogBubbleColors( backgroundColor = MaterialTheme.colorScheme.surfaceVariant ) ) ) ``` -------------------------------- ### Create Basic Bubble Content Settings Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Use this function to create basic bubble content with standard layout. It accepts various parameters for customization, including button texts, click handlers, and colors. ```kotlin fun bubbleContentBasicSettings( modifier: Modifier = Modifier, title: String, description: String, primaryButtonText: String? = null, secondaryButtonText: String? = null, onDismiss: () -> Unit = {}, onPrimaryClick: () -> Unit = {}, onSecondaryClick: () -> Unit = {}, colors: BubbleContentColors? = null ): BubbleContentSettings ``` -------------------------------- ### Wrap Activity Content with TourComposeWrapper Source: https://context7.com/antoniohreyes/tourcompose/llms.txt Integrate TourCompose by wrapping the root of your Composable content within `TourComposeWrapper`. This makes the tour controller available throughout the composition. ```kotlin class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { AppTheme { TourComposeWrapper(tourController = remember { MainTourController() }) { MainContent() } } } } } ``` -------------------------------- ### Define Tour Controller and Steps Source: https://context7.com/antoniohreyes/tourcompose/llms.txt Define a custom TourComposeController, adding tours with specific steps, IDs, and bubble content settings. Use `nextStep()`, `previousStep()`, and `stopTour()` for navigation and control. ```kotlin class MainTourController : TourComposeController() { companion object { const val FLOW = "main_tour" } init { addTour(flowId = FLOW, steps = listOf( TourComposeStep( id = "fab", bubbleContentSettings = bubbleContentMaterial3( title = "Create New", description = "Tap the + button to create a new item.", primaryButtonText = "Next", onPrimaryClick = { nextStep() }, onDismiss = { stopTour() } ) ), TourComposeStep( id = "list", bubbleContentSettings = bubbleContentMaterial3( title = "Your Items", description = "All your created items appear here.", primaryButtonText = "Done", secondaryButtonText = "Back", onPrimaryClick = { stopTour() }, onSecondaryClick = { previousStep() }, onDismiss = { stopTour() } ) ) )) } } ``` -------------------------------- ### Use Material3-aware Tour Overlay with TourComposeMaterial3 Source: https://context7.com/antoniohreyes/tourcompose/llms.txt Use `TourComposeMaterial3` for Material 3 integration. It automatically adapts spotlight and bubble colors to the current `MaterialTheme.colorScheme`, supporting light/dark modes. Optional `TourComposeMaterial3Properties` can be provided for customization. ```kotlin currentStep?.let { TourComposeMaterial3( componentRectArea = step.componentRect, bubbleContentSettings = step.bubbleContentSettings ) } ``` -------------------------------- ### Add TourCompose Dependency Source: https://context7.com/antoniohreyes/tourcompose/llms.txt Configure JitPack and add the TourCompose dependency to your project. Choose the Material3 module for automatic theming or the core module for custom design control. ```kotlin dependencyResolutionManagement { repositories { google() mavenCentral() maven { url = uri("https://jitpack.io") } } } // Option A: Material3 integration (includes core automatically via api dependency) dependencies { implementation("com.github.AntonioHReyes.TourCompose:tourcompose-material3:2.0.0") } // Option B: Core only (design-system agnostic) dependencies { implementation("com.github.AntonioHReyes.TourCompose:tourcompose:2.0.0") } ``` -------------------------------- ### SpotlightColors Interface Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Interface for customizing the overlay and spotlight colors within the tour UI. ```kotlin interface SpotlightColors { val overlayBackgroundColor: Color val overlayBorderColor: Color } ``` -------------------------------- ### Create Progress Bubble Content in Kotlin Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Defines a custom `BubbleContentSettings` for tour bubbles that includes a progress indicator and navigation buttons. Use this to display step-by-step information with clear progress tracking. ```kotlin @Immutable class ProgressBubbleContent( override val modifier: Modifier = Modifier, override val title: String, override val description: String, val currentStep: Int, val totalSteps: Int, val progress: Float, override val onDismiss: () -> Unit, val onNext: () -> Unit, val onPrevious: () -> Unit ) : BubbleContentSettings { @Composable override fun DrawContent(modifier: Modifier) { Card( modifier = modifier, colors = CardDefaults.cardColors( containerColor = MaterialTheme.colorScheme.surface, contentColor = MaterialTheme.colorScheme.onSurface ) ) { Column( modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(12.dp) ) { // Header with title and close button Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { Text( text = title, style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold ) IconButton(onClick = onDismiss) { Icon( imageVector = Icons.Default.Close, contentDescription = "Close" ) } } // Progress indicator Column { Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween ) { Text( text = "Progress", style = MaterialTheme.typography.bodySmall ) Text( text = "$currentStep/$totalSteps", style = MaterialTheme.typography.bodySmall ) } LinearProgressIndicator( progress = { progress }, modifier = Modifier.fillMaxWidth() ) } // Description Text( text = description, style = MaterialTheme.typography.bodyMedium ) // Action buttons Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.End) ) { if (currentStep > 1) { OutlinedButton(onClick = onPrevious) { Text("Previous") } } Button(onClick = onNext) { Text(if (currentStep < totalSteps) "Next" else "Finish") } } } } } } // Usage fun createProgressTourSteps() = listOf( TourComposeStep( id = "step1", bubbleContentSettings = ProgressBubbleContent( title = "Step 1: Getting Started", description = "Welcome to our comprehensive tour!", currentStep = 1, totalSteps = 3, progress = 0.33f, onNext = { nextStep() }, onPrevious = { /* no previous */ }, onDismiss = { stopTour() } ) ), // ... more steps ) ``` -------------------------------- ### SpotlightColors Interface Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Defines colors for the tour's overlay and spotlight. ```APIDOC ## SpotlightColors Customizes the overlay and spotlight appearance. ### Properties - **overlayBackgroundColor** (Color) - The background color of the overlay. - **overlayBorderColor** (Color) - The border color of the overlay. ``` -------------------------------- ### Basic TourCompose Color Customization Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Customize spotlight and dialog bubble colors for the `TourCompose` component. Use `TourComposeProperties.getDefaultInstance().copy()` for modifications. ```kotlin TourCompose( componentRectArea = currentStep?.componentRect, bubbleContentSettings = currentStep?.bubbleContentSettings, tourComposeProperties = TourComposeProperties.getDefaultInstance().copy( spotlightColors = defaultSpotlightColors().copy( overlayBackgroundColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.8f), overlayBorderColor = MaterialTheme.colorScheme.secondary ), dialogBubbleColors = defaultDialogBubbleColors().copy( backgroundColor = MaterialTheme.colorScheme.primaryContainer ) ) ) ``` -------------------------------- ### bubbleContentBasicSettings Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Creates basic bubble content with a standard layout. This function is used to configure the appearance and behavior of tour bubbles. ```APIDOC ## bubbleContentBasicSettings ### Description Creates basic bubble content with standard layout. ### Signature ```kotlin fun bubbleContentBasicSettings( modifier: Modifier = Modifier, title: String, description: String, primaryButtonText: String? = null, secondaryButtonText: String? = null, onDismiss: () -> Unit = {}, onPrimaryClick: () -> Unit = {}, onSecondaryClick: () -> Unit = {}, colors: BubbleContentColors? = null ): BubbleContentSettings ``` ``` -------------------------------- ### Test TourController Functionality Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Write unit tests for TourController to verify tour creation, navigation, and completion states. Use assertions to check controller behavior. ```kotlin @Test fun testTourController() { val controller = MyTourController() // Test tour creation controller.startTour("welcome_tour") assert(controller.isActive) // Test navigation controller.nextStep() controller.previousStep() // Test completion controller.stopTour() assert(!controller.isActive) } ``` -------------------------------- ### Optimize TourController Recreation with remember Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Use the remember composable to avoid unnecessary recreation of tour controllers. Employ keys for dynamic controllers that depend on changing state. ```kotlin // Use remember to avoid recreating tour controllers val tourController = remember { MyTourController() } // Use keys in remember for dynamic controllers val dynamicController = remember(userType, featureFlags) { createDynamicTourController(userType, featureFlags) } ``` -------------------------------- ### Add JitPack Repository to build.gradle.kts Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Add the JitPack repository to your project-level build.gradle.kts file to enable dependency resolution for TourCompose. ```kotlin allprojects { repositories { google() mavenCentral() maven { url = uri("https://jitpack.io") } } } ``` -------------------------------- ### Add Both TourCompose Modules Dependency Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Include both the core library and the Material3 integration module for advanced usage scenarios where both custom and Material3 designs are needed. ```kotlin dependencies { implementation("com.github.AntonioHReyes.TourCompose:tourcompose:") implementation("com.github.AntonioHReyes.TourCompose:tourcompose-material3:") // Useful when you need both custom and Material3 designs in the same app } ``` -------------------------------- ### Mark Tour Targets and Render Overlay Source: https://context7.com/antoniohreyes/tourcompose/llms.txt Use the `tourStepIndex` modifier to mark UI elements as tour targets and conditionally render the `TourComposeMaterial3` overlay based on the current tour step. Auto-start tours on first run using `LaunchedEffect`. ```kotlin @Composable fun TourComposeScope.MainContent() { val tourController = LocalTourController.current val currentStep by tourController.currentStep.collectAsState(initial = null) Scaffold( floatingActionButton = { FloatingActionButton( modifier = Modifier.tourStepIndex(MainTourController.FLOW, 0), onClick = {} ) { Icon(Icons.Default.Add, null) } } ) { LazyColumn( modifier = Modifier .padding(padding) .tourStepIndex(MainTourController.FLOW, 1) ) { items(sampleItems) { item -> ItemRow(item) } } currentStep?.let { TourComposeMaterial3( componentRectArea = it.componentRect, bubbleContentSettings = it.bubbleContentSettings ) } LaunchedEffect(Unit) { if (prefsRepository.isFirstRun()) { tourController.startTour(MainTourController.FLOW) } } } } ``` -------------------------------- ### Add TourCompose Core Library Only Dependency Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Use this dependency if you intend to create your own design system integration or only need the core tour functionality. ```kotlin dependencies { implementation("com.github.AntonioHReyes.TourCompose:tourcompose:") // Use this if you want to create your own design system integration } ``` -------------------------------- ### TourComposeProperties Data Class Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Main configuration object for customizing the appearance of tours, including spotlight and dialog bubble colors. ```kotlin data class TourComposeProperties( val spotlightColors: SpotlightColors, val dialogBubbleColors: DialogBubbleColors ) ``` -------------------------------- ### TourComposeProperties Configuration Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Configuration class for customizing the overall appearance of TourCompose. ```APIDOC ## TourComposeProperties Main configuration object for customizing appearance. ### Properties - **spotlightColors** (SpotlightColors) - Customizes the overlay and spotlight appearance. - **dialogBubbleColors** (DialogBubbleColors) - Customizes the bubble background. ``` -------------------------------- ### Add JitPack Repository to settings.gradle.kts Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Alternatively, add the JitPack repository to your settings.gradle.kts file in newer Android projects for dependency resolution. ```kotlin dependencyResolutionManagement { repositories { google() mavenCentral() maven { url = uri("https://jitpack.io") } } } ``` -------------------------------- ### Display Tour Overlay with TourCompose Source: https://context7.com/antoniohreyes/tourcompose/llms.txt The `TourCompose` composable renders the main tour overlay, including a dimmed background and a spotlight around the target component. It automatically positions the info bubble based on the component's screen position. Pass `componentRectArea` and `bubbleContentSettings` from the `currentStep` flow. ```kotlin currentStep?.let { TourCompose( tourComposeProperties = TourComposeProperties.getDefaultInstance(), componentRectArea = step.componentRect, bubbleContentSettings = step.bubbleContentSettings ) } ``` -------------------------------- ### BubbleContentSettings Interface Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Interface for creating custom content within tour bubbles. ```APIDOC ## BubbleContentSettings Interface for creating custom bubble content. ### Properties - **modifier** (Modifier) - Modifier to be applied to the content. - **title** (String) - The title text for the bubble. - **description** (String) - The description text for the bubble. - **onDismiss** ( () -> Unit ) - Callback function invoked when the bubble is dismissed. ### Composable Functions - **DrawContent(modifier: Modifier)**: A composable function where custom bubble content can be drawn. ``` -------------------------------- ### Wrap Content with TourComposeWrapper for Context Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Use TourComposeWrapper to provide the tour controller context to your composable tree. This is essential for any composables that need to interact with the tour. ```kotlin @Composable fun TestTourWrapper(content: @Composable () -> Unit) { val testController = remember { TestTourController() } TourComposeWrapper(tourController = testController) { content() } } ``` -------------------------------- ### BubbleContentColors Interface Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Interface for customizing text and icon colors within the tour bubbles. ```kotlin interface BubbleContentColors { val titleTextColor: Color val descriptionTextColor: Color val iconTintColor: Color val dividerColor: Color } ``` -------------------------------- ### Define Interactive Bubble Content Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Defines a reusable composable for interactive tour bubbles with options and actions. Use this to create custom content for tour steps. ```kotlin import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.Card import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import com.example.tourcompose.core.settings.BubbleContentSettings @Immutable class InteractiveBubbleContent( override val modifier: Modifier = Modifier, override val title: String, override val description: String, val options: List, val onOptionSelected: (String) -> Unit, override val onDismiss: () -> Unit ) : BubbleContentSettings { @Composable override fun DrawContent(modifier: Modifier) { Card(modifier = modifier) { Column( modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { Text( text = title, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold ) Text( text = description, style = MaterialTheme.typography.bodyMedium ) // Interactive options options.forEach { option -> OutlinedButton( onClick = { onOptionSelected(option) }, modifier = Modifier.fillMaxWidth() ) { Text(option) } } // Close button TextButton( onClick = onDismiss, modifier = Modifier.align(Alignment.End) ) { Text("Skip") } } } } } ``` -------------------------------- ### Dynamically Add/Remove Tours with Controller Methods Source: https://context7.com/antoniohreyes/tourcompose/llms.txt Use `addTour` and `removeTour` to register or unregister tour flows. These methods support dynamic tour construction based on feature flags or user state, allowing tours to be added or removed after initialization. ```kotlin class DynamicTourController( private val featureFlags: FeatureFlags ) : TourComposeController() { init { // Always add base onboarding addTour(flowId = "base", steps = buildBaseSteps()) // Conditionally add feature tours if (featureFlags.isAnalyticsEnabled) { addTour(flowId = "analytics_tour", steps = buildAnalyticsSteps()) } } fun refreshTours(newFlags: FeatureFlags) { // Remove stale tour if feature was disabled if (!newFlags.isAnalyticsEnabled) { removeTour("analytics_tour") } // Add new tour if feature was enabled if (newFlags.isNewDashboardEnabled) { addTour(flowId = "dashboard_tour", steps = buildDashboardSteps()) } } } ``` -------------------------------- ### Enable Edge-to-Edge Support in MainActivity Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Call enableEdgeToEdge() in your MainActivity to allow TourCompose to automatically adapt to edge-to-edge displays and manage safe areas. ```kotlin // In your MainActivity class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() // TourCompose will automatically adapt setContent { // Your content - TourCompose handles safe areas automatically } } } ``` -------------------------------- ### Customize Bubble Content Colors Source: https://context7.com/antoniohreyes/tourcompose/llms.txt Configure text and icon colors for basic bubbles using BubbleContentColors and its copy() helper for incremental overrides. For Material3, use material3BubbleContentColors() to align with the theme. ```kotlin // Custom branded colors for the basic (non-Material3) module val brandColors = defaultBubbleContentColors().copy( titleTextColor = Color(0xFFE91E63), // brand pink title descriptionTextColor = Color(0xFF880E4F), // darker pink body iconTintColor = Color(0xFFFF4081), // accent close icon dividerColor = Color(0xFFF48FB1) // soft pink divider ) // Use in bubbleContentBasicSettings bubbleContentBasicSettings( title = "Brand Tour", description = "Experience our fully branded tour flow.", primaryButtonText = "Next", colors = brandColors, onPrimaryClick = { nextStep() }, onDismiss = { stopTour() } ) ``` ```kotlin // Material3 variant — override only the title, keep other tokens from theme val m3Colors = material3BubbleContentColors().copy( titleTextColor = MaterialTheme.colorScheme.error // highlight titles in error color ) ``` -------------------------------- ### TourComposeWrapper Composable Signature Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Provides tour controller context to the composition tree. It takes a TourComposeController and a content lambda. ```kotlin @Composable fun TourComposeWrapper( tourController: TourComposeController, content: @Composable TourComposeScope.() -> Unit ) ``` -------------------------------- ### DialogBubbleColors Interface Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Interface for customizing the background color of the tour's dialog bubbles. ```kotlin interface DialogBubbleColors { val backgroundColor: Color } ``` -------------------------------- ### Add TourCompose Material3 Integration Dependency Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Include the Material3 integration module for automatic theming support. This dependency also includes the base TourCompose library. ```kotlin dependencies { implementation("com.github.AntonioHReyes.TourCompose:tourcompose-material3:") // This automatically includes the base TourCompose library via api dependency } ``` -------------------------------- ### BubbleContentColors Interface Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Defines colors for text and icons within tour bubbles. ```APIDOC ## BubbleContentColors Customizes text and icon colors within bubbles. ### Properties - **titleTextColor** (Color) - The text color for the bubble title. - **descriptionTextColor** (Color) - The text color for the bubble description. - **iconTintColor** (Color) - The tint color for icons within the bubble. - **dividerColor** (Color) - The color of the divider line in the bubble. ``` -------------------------------- ### TourComposeController Methods Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Methods available on the TourComposeController for managing tour lifecycles and navigation. ```APIDOC ## TourComposeController Base class for managing tour logic and state. ### Methods - **startTour(flowId: String)**: Starts a tour identified by its flow ID. - **stopTour()**: Stops the currently active tour. - **nextStep()**: Advances to the next step in the current tour. - **previousStep()**: Moves to the previous step in the current tour. - **addTour(flowId: String, steps: List)**: Adds a new tour definition. ### Properties - **currentStep**: StateFlow - Represents the current step of the tour. - **isActive**: Boolean - Indicates whether a tour is currently active. ``` -------------------------------- ### MIT License Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md The MIT License governs the use, modification, and distribution of the software. It includes a disclaimer of warranty and limits liability. ```text MIT License Copyright (c) 2024 Antonio Huerta Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` -------------------------------- ### Create Material3 Bubble Content Source: https://context7.com/antoniohreyes/tourcompose/llms.txt Use `bubbleContentMaterial3` to create `BubbleContentSettings` with Material3 components. It defaults to `material3BubbleContentColors` which uses `MaterialTheme.colorScheme` tokens. You can optionally override specific colors. ```kotlin val step = TourComposeStep( id = "profile_step", bubbleContentSettings = bubbleContentMaterial3( title = "Your Profile", description = "Tap your avatar to update your photo, bio, and account settings.", primaryButtonText = "Got It", secondaryButtonText = "Back", // Optionally override individual colors while keeping Material3 defaults for others: colors = material3BubbleContentColors().copy( titleTextColor = MaterialTheme.colorScheme.primary ), onPrimaryClick = { nextStep() }, onSecondaryClick = { previousStep() }, onDismiss = { stopTour() } ) ) ``` -------------------------------- ### TourCompose Composable Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md The main composable function for rendering tour overlays. ```APIDOC ## TourCompose Main composable that renders the tour overlay. ### Parameters - **tourComposeProperties** (TourComposeProperties) - Optional - Main configuration object for customizing appearance. Defaults to `TourComposeProperties.getDefaultInstance()`. - **componentRectArea** (Rect?) - Optional - The rectangular area of the component to highlight. - **bubbleContentSettings** (BubbleContentSettings?) - Optional - Settings for the bubble content displayed during the tour. ``` -------------------------------- ### Access Tour Controller with LocalTourController Source: https://context7.com/antoniohreyes/tourcompose/llms.txt Retrieve the current TourComposeController using LocalTourController.current within a TourComposeWrapper subtree to trigger tour navigation without explicit prop drilling. ```kotlin @Composable fun OnboardingStartButton() { val tourController = LocalTourController.current Button( onClick = { tourController.startTour(AppTourController.ONBOARDING_FLOW) } ) { Text("Start Tour") } } ``` ```kotlin @Composable fun ConditionalTourLauncher(isFirstRun: Boolean, hasNewFeature: Boolean) { val tourController = LocalTourController.current LaunchedEffect(isFirstRun, hasNewFeature) { when { isFirstRun -> tourController.startTour(AppTourController.ONBOARDING_FLOW) hasNewFeature -> tourController.startTour(AppTourController.FEATURE_FLOW) } } } ``` -------------------------------- ### BubbleContentSettings Interface Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Interface for creating custom bubble content. It defines properties for modifiers, title, description, dismiss action, and a composable function to draw the content. ```kotlin interface BubbleContentSettings { val modifier: Modifier val title: String val description: String val onDismiss: () -> Unit @Composable fun DrawContent(modifier: Modifier) } ``` -------------------------------- ### Default Color Functions Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Provides functions to create default color schemes that adapt to the Material Theme, ensuring visual consistency. ```APIDOC ## Default Color Functions ### Description Create default color schemes that adapt to Material Theme. ### Signatures ```kotlin @Composable fun defaultSpotlightColors(): SpotlightColors @Composable fun defaultDialogBubbleColors(): DialogBubbleColors @Composable fun defaultBubbleContentColors(): BubbleContentColors ``` ``` -------------------------------- ### DialogBubbleColors Interface Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Defines colors for the tour's dialog bubble background. ```APIDOC ## DialogBubbleColors Customizes the bubble background. ### Properties - **backgroundColor** (Color) - The background color of the dialog bubble. ``` -------------------------------- ### TourComposeWrapper Composable Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md A wrapper composable that provides the TourComposeController context to its children. ```APIDOC ## TourComposeWrapper Provides tour controller context to the composition tree. ### Parameters - **tourController** (TourComposeController) - Required - The controller instance to be provided. - **content** (@Composable TourComposeScope.() -> Unit) - Required - The content to be wrapped, which can access the tour controller context. ``` -------------------------------- ### Mark Components as Tour Targets Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Applies a modifier to components to mark them as targets within a tour. Requires the flow ID and the step index for proper identification. ```kotlin fun Modifier.tourStepIndex(flowId: String, stepIndex: Int): Modifier ``` -------------------------------- ### TourCompose Composable Signature Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md The main TourCompose composable for rendering tour overlays. It accepts properties, component rect area, and bubble content settings. ```kotlin @Composable fun TourCompose( tourComposeProperties: TourComposeProperties = TourComposeProperties.getDefaultInstance(), componentRectArea: Rect?, bubbleContentSettings: BubbleContentSettings? ) ``` -------------------------------- ### Mark Target Components with tourStepIndex Source: https://github.com/antoniohreyes/tourcompose/blob/master/README.md Use the `tourStepIndex` modifier on composable components to define which step of a tour they correspond to. Ensure the `TourComposeScope` is available. ```kotlin @Composable fun TourComposeScope.MyContent() { Column { // Step 1: Welcome message Text( modifier = Modifier.tourStepIndex(WELCOME_TOUR, 0), text = "Welcome to our app!", style = MaterialTheme.typography.headlineMedium ) // Step 2: Action button Button( modifier = Modifier.tourStepIndex(WELCOME_TOUR, 1), onClick = { /* action */ } ) { Text("Get Started") } // Step 3: Menu IconButton( modifier = Modifier.tourStepIndex(WELCOME_TOUR, 2), onClick = { /* menu action */ } ) { Icon(Icons.Default.Menu, contentDescription = "Menu") } } } ```