Skip to main content
This guide walks you through performing your first inventory scan operation using the EnvaSistema mobile application. You’ll learn how to navigate the interface and complete a production intake scan.

Prerequisites

Before you begin, ensure you have:
  • The EnvaSistema mobile app installed on your handheld device
  • An active user account with proper credentials
  • Terminal configured and connected (device should show “ONLINE” status)
  • Access to the production floor or warehouse area with scannable QR codes

Understanding the Home Screen

When you launch the app, you’ll see the main HomeScreen with four primary operation categories:
HomeScreen.kt
MenuCard(
    title = "INGRESOS",
    subtitle = "Producción, armados y devoluciones",
    icon = Icons.Default.AddBox,
    onClick = onIngresosClick
)
MenuCard(
    title = "SALIDAS",
    subtitle = "Ventas, paquetes, mermas y donaciones",
    icon = Icons.Default.DoubleArrow,
    onClick = onSalidasClick
)
MenuCard(
    title = "MOVIMIENTOS",
    subtitle = "Transferencia entre ubicaciones",
    icon = Icons.Default.SwapHoriz,
    onClick = onMovimientosClick
)
MenuCard(
    title = "TRANSFORMACIONES",
    subtitle = "Desarmar paquetes de producto terminado",
    icon = Icons.Default.Build,
    onClick = onTransformacionesClick
)
The home screen header displays:
  • Device status (e.g., “C66 · ONLINE”)
  • Current user (e.g., “J. PÉREZ”)
  • Date and shift information (e.g., “Lun, 9 de Marzo 2026” / “Turno Mañana”)
1
Select an Operation Type
2
From the home screen, tap on INGRESOS (Inbound Operations). This section handles:
3
  • Production intake (Producción Nueva)
  • Assembly intake (Ingreso Armado)
  • Unassembled returns (Devolución No Armado)
  • Merchandise returns (Devolución Mercadería)
  • 4
    The app uses a navigation-based architecture. Each screen in the workflow is defined in AppNavigation.kt and follows a consistent pattern for user interaction.
    5
    Choose Production Intake
    6
    Select Producción Nueva to begin scanning newly produced items. The app will navigate to the scanning interface:
    7
    composable(Screen.ProduccionNueva.route) {
        ProduccionNuevaScreen(onBackClick = { navController.popBackStack() })
    }
    
    8
    Review the Scanning Interface
    9
    The ProduccionNuevaScreen displays:
    10
  • Header section - Shows operation type and category
  • Info card - Instructions for the current operation
  • Scan area - Large interactive zone with QR code scanner icon
  • Counter - Tracks number of codes scanned
  • Save button - Enabled when at least one code is scanned
  • 11
    // Info Alert Card
    Surface(
        modifier = Modifier.fillMaxWidth(),
        color = Color(0xFFE1F5FE),
        shape = RoundedCornerShape(12.dp)
    ) {
        Row(
            modifier = Modifier.fillMaxWidth(),
            verticalAlignment = Alignment.CenterVertically
        ) {
            Box(modifier = Modifier.width(6.dp).height(60.dp).background(Color(0xFF0061A6)))
            
            Icon(
                imageVector = Icons.Default.RadioButtonChecked,
                contentDescription = null,
                tint = Color(0xFF0061A6),
                modifier = Modifier.padding(horizontal = 12.dp).size(24.dp)
            )
            Text(
                text = "Presione botón lateral para escanear código QR de la pieza / manga",
                color = Color(0xFF0061A6),
                fontSize = 14.sp,
                fontWeight = FontWeight.Medium
            )
        }
    }
    
    12
    Scan QR Codes
    13
    Use the physical side button on your handheld terminal to trigger the scanner. Do not attempt to use the device camera or touchscreen for scanning.
    14
    To scan items:
    15
  • Position the terminal 4-6 inches from the QR code
  • Press and hold the side scan button
  • Wait for the beep confirmation
  • The counter will increment automatically
  • 16
    // Scan Area Implementation
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .height(200.dp)
            .border(1.dp, Color(0xFFBDBDBD), RoundedCornerShape(16.dp))
            .clip(RoundedCornerShape(16.dp))
            .clickable { scannCount++ },
        contentAlignment = Alignment.Center
    ) {
        Column(horizontalAlignment = Alignment.CenterHorizontally) {
            Surface(
                color = Color(0xFFEEEEEE),
                shape = CircleShape,
                modifier = Modifier.size(80.dp)
            ) {
                Icon(
                    imageVector = Icons.Default.QrCodeScanner,
                    contentDescription = null,
                    tint = Color(0xFF9E9E9E),
                    modifier = Modifier.padding(20.dp)
                )
            }
            Spacer(modifier = Modifier.height(16.dp))
            Text(
                text = "Presione el botón lateral del terminal para escanear",
                color = Color(0xFF607D8B),
                fontSize = 14.sp,
                textAlign = TextAlign.Center
            )
        }
    }
    
    17
    The ScanningLayout component is reusable across different operation types and provides consistent scanning behavior throughout the app.
    18
    Monitor Progress
    19
    As you scan, watch the counter update in real-time:
    20
    // Scanned Codes Counter
    Row(
        modifier = Modifier.fillMaxWidth(),
        verticalAlignment = Alignment.CenterVertically
    ) {
        Surface(
            color = Color(0xFF0061A6),
            shape = CircleShape,
            modifier = Modifier.size(32.dp)
        ) {
            Box(contentAlignment = Alignment.Center) {
                Text(text = scannCount.toString(), color = Color.White, fontWeight = FontWeight.Bold)
            }
        }
        Spacer(modifier = Modifier.width(12.dp))
        Text(
            text = "Códigos escaneados",
            color = Color(0xFF455A64),
            fontSize = 16.sp,
            fontWeight = FontWeight.Bold
        )
    }
    
    21
    The circular badge displays the total number of scanned items, providing instant visual feedback.
    22
    Save Your Work
    23
    Once you’ve scanned all items:
    24
  • Verify the count matches your physical inventory
  • Tap the “Guardar Ingreso” button at the bottom
  • Wait for confirmation
  • 25
    Button(
        onClick = { /* TODO */ },
        modifier = Modifier
            .fillMaxWidth()
            .height(56.dp),
        shape = RoundedCornerShape(16.dp),
        colors = ButtonDefaults.buttonColors(
            containerColor = if (scannCount > 0) Color(0xFF0061A6) else Color(0xFFB0BEC5),
            contentColor = Color.White
        )
    ) {
        Icon(imageVector = Icons.Default.Save, contentDescription = null)
        Spacer(modifier = Modifier.width(8.dp))
        Text(text = "Guardar Ingreso", fontSize = 18.sp, fontWeight = FontWeight.Bold)
    }
    
    26
    The save button is automatically disabled (gray) when no codes have been scanned. It becomes active (blue) as soon as you scan your first item.

    Understanding the ScanningLayout Component

    The app uses a reusable ScanningLayout component that powers all scanning operations. This component handles:
    • State management - Tracks scan count with mutableIntStateOf
    • Dynamic styling - Adapts colors based on operation type
    • Validation - Controls button enablement via isSaveButtonEnabled lambda
    • Extensibility - Supports extra content through composable slots
    ScanningLayout.kt
    @Composable
    fun ScanningLayout(
        title: String,
        subtitle: String,
        infoText: String,
        onBackClick: () -> Unit,
        onSaveClick: (Int) -> Unit,
        counterLabel: String = "Códigos escaneados",
        saveButtonText: String = "Guardar Ingreso",
        saveButtonIcon: ImageVector = Icons.Default.Save,
        primaryColor: Color = Color(0xFF0061A6),
        infoCardBackground: Color = Color(0xFFE1F5FE),
        infoIcon: ImageVector = Icons.Default.Radar,
        infoIconColor: Color? = null,
        isSaveButtonEnabled: ((Int) -> Boolean)? = null,
        extraContent: @Composable (ColumnScope.() -> Unit)? = null
    )
    
    This component is used across multiple screens:
    • ProduccionNuevaScreen - New production intake
    • IngresoArmadoScreen - Assembly intake
    • VentaPTScreen - Finished product sales
    • TransferenciaInventarioScreen - Inventory transfers
    The app follows a hierarchical navigation structure:
    AppNavigation.kt
    sealed class Screen(val route: String) {
        object Home : Screen("home")
        
        // Ingresos
        object Ingresos : Screen("ingresos")
        object ProduccionNueva : Screen("produccion_nueva")
        object IngresoArmado : Screen("ingreso_armado")
        object DevolucionNoArmado : Screen("devolucion_no_armado")
        object DevolucionMercaderia : Screen("devolucion_mercaderia")
        
        // Salidas
        object Salidas : Screen("salidas")
        object VentaPT : Screen("venta_pt")
        object ArmarPaquetes : Screen("armar_paquetes")
        object MermaMolino : Screen("merma_molino")
        object Donaciones : Screen("donaciones")
        
        // Others
        object Movimientos : Screen("movimientos")
        object Transformaciones : Screen("transformaciones")
    }
    
    Each screen can navigate back using the onBackClick callback, which calls navController.popBackStack().

    Common Patterns

    Color Coding by Operation Type

    Different operations use distinct color schemes:
    • Ingresos (Inbound) - Blue (0xFF0061A6)
    • Salidas (Outbound) - Varies by sub-operation
    • Movimientos (Transfers) - Gray (0xFF455A64)
    • Transformaciones (Transformations) - Red (0xFFB71C1C)

    Consistent UI Structure

    All scanning screens follow this structure:
    1. SecondaryHeader - Title, subtitle, back button
    2. Info card - Operation-specific instructions
    3. Scan area - Large tap target with QR icon
    4. Counter row - Badge + label
    5. Empty state - “No hay códigos escaneados”
    6. Action button - Context-specific save/submit

    Tips for Efficient Scanning

    Best Practices

    • Hold the terminal steady at optimal distance (4-6 inches)
    • Ensure adequate lighting for QR code visibility
    • Wait for the beep before moving to the next item
    • Verify the counter increments after each scan
    • Review total count before saving

    Troubleshooting

    • If scan fails, clean the scanner lens
    • Check that device shows “ONLINE” status
    • Ensure QR codes are not damaged or obscured
    • Restart the app if counter doesn’t update
    Always complete your scanning session by tapping the save button. Navigating back without saving will discard all scanned data.

    Next Steps

    Now that you’ve completed your first inventory operation, explore these topics:

    System Architecture

    Learn about the app’s technical structure and component organization

    UI Components

    Deep dive into reusable components like ScanningLayout and MenuCard

    Inbound Operations

    Explore all types of inbound operations and their specific workflows

    Development Setup

    Set up your development environment to customize the app

    Build docs developers (and LLMs) love