Skip to main content
The Campus Map Screen helps students navigate the TecNM campus by providing a visual map and searchable list of buildings, classrooms, laboratories, and other facilities.

Overview

Built with Jetpack Compose, the Campus Map features a simulated campus layout with building markers and a filterable list of nearby locations. This feature is designed to help students quickly find their classrooms and navigate the campus.
The current implementation uses a simulated map visualization. Future updates will integrate a real interactive map with GPS functionality.

Data Model

The map uses the Building data class to represent campus locations:
Building.kt
data class Building(
    val id: Int,
    val name: String,
    val description: String,
    val category: String,
    val distance: String
)

UI Components

MapHeader

The header provides context and instructions for the campus locator:
MapScreen.kt:162-201
@Composable
fun MapHeader() {
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .background(
                color = TecBlue,
                shape = RoundedCornerShape(bottomStart = 32.dp, bottomEnd = 32.dp)
            )
            .padding(20.dp)
    ) {
        Column {
            Spacer(modifier = Modifier.height(10.dp))

            Text(
                text = "CAMPUS LOCATOR",
                color = Color.White.copy(alpha = 0.70f),
                style = MaterialTheme.typography.labelLarge
            )

            Spacer(modifier = Modifier.height(6.dp))

            Text(
                text = "Mapa del campus",
                color = Color.White,
                style = MaterialTheme.typography.headlineLarge,
                fontWeight = FontWeight.Bold
            )

            Spacer(modifier = Modifier.height(8.dp))

            Text(
                text = "Encuentra rápidamente edificios, aulas y laboratorios",
                color = Color.White.copy(alpha = 0.85f),
                style = MaterialTheme.typography.bodyLarge
            )

            Spacer(modifier = Modifier.height(10.dp))
        }
    }
}
An outlined text field with search functionality:
MapScreen.kt:84-104
OutlinedTextField(
    value = searchText.value,
    onValueChange = { searchText.value = it },
    modifier = Modifier.fillMaxWidth(),
    placeholder = {
        Text("Buscar edificio o aula")
    },
    leadingIcon = {
        Icon(
            imageVector = Icons.Outlined.Search,
            contentDescription = "Buscar"
        )
    },
    shape = RoundedCornerShape(20.dp),
    colors = OutlinedTextFieldDefaults.colors(
        focusedBorderColor = TecBlue,
        unfocusedBorderColor = Color(0xFFD6DCE5),
        focusedContainerColor = Color.White,
        unfocusedContainerColor = Color.White
    )
)
Features:
  • White background with rounded corners
  • TecBlue border when focused
  • Search icon on the left
  • Placeholder text: “Buscar edificio o aula” (Search building or classroom)

FilterChipCustom

Category filter chips for narrowing building results:
MapScreen.kt:204-220
@Composable
fun FilterChipCustom(text: String, selected: Boolean) {
    Card(
        shape = RoundedCornerShape(50.dp),
        colors = CardDefaults.cardColors(
            containerColor = if (selected) TecBlue else Color.White
        ),
        elevation = CardDefaults.cardElevation(defaultElevation = 2.dp),
        modifier = Modifier.wrapContentHeight()
    ) {
        Text(
            text = text,
            modifier = Modifier.padding(horizontal = 16.dp, vertical = 10.dp),
            color = if (selected) Color.White else Color(0xFF475569),
            fontWeight = FontWeight.SemiBold
        )
    }
}
Filter categories:
  • Todos (All) - Selected by default
  • Aulas (Classrooms)
  • Labs (Laboratories)
  • Cafetería (Cafeteria)

CampusMapCard

A visual representation of the campus layout:
MapScreen.kt:223-321
@Composable
fun CampusMapCard() {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .height(320.dp),
        shape = RoundedCornerShape(28.dp),
        colors = CardDefaults.cardColors(containerColor = Color.White),
        elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
    ) {
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(Color(0xFFF8FAFC))
        ) {
            Box(
                modifier = Modifier
                    .matchParentSize()
                    .padding(20.dp)
                    .border(
                        width = 1.dp,
                        color = Color(0xFFE2E8F0),
                        shape = RoundedCornerShape(20.dp)
                    )
            )

            // Building A
            Box(
                modifier = Modifier
                    .size(width = 110.dp, height = 64.dp)
                    .offset(x = 28.dp, y = 42.dp)
                    .background(Color(0xFFDCEBFF), RoundedCornerShape(18.dp)),
                contentAlignment = Alignment.Center
            ) {
                Text(
                    text = "Edificio A",
                    color = TecBlue,
                    fontWeight = FontWeight.Bold
                )
            }

            // Lab 3
            Box(
                modifier = Modifier
                    .size(width = 130.dp, height = 72.dp)
                    .offset(x = 180.dp, y = 82.dp)
                    .background(Color(0xFFE7FAF1), RoundedCornerShape(18.dp)),
                contentAlignment = Alignment.Center
            ) {
                Text(
                    text = "Lab 3",
                    color = Color(0xFF0F9F6E),
                    fontWeight = FontWeight.Bold
                )
            }

            // Cafeteria
            Box(
                modifier = Modifier
                    .size(width = 116.dp, height = 62.dp)
                    .offset(x = 90.dp, y = 210.dp)
                    .background(Color(0xFFFFF1E8), RoundedCornerShape(18.dp)),
                contentAlignment = Alignment.Center
            ) {
                Text(
                    text = "Cafetería",
                    color = Color(0xFFFF7A00),
                    fontWeight = FontWeight.Bold
                )
            }

            // Current location marker
            Box(
                modifier = Modifier
                    .size(22.dp)
                    .offset(x = 250.dp, y = 200.dp)
                    .background(TecGold, CircleShape)
            )

            // Map label
            Box(
                modifier = Modifier
                    .align(Alignment.BottomStart)
                    .padding(16.dp)
                    .background(Color.White, RoundedCornerShape(16.dp))
                    .padding(horizontal = 14.dp, vertical = 10.dp)
            ) {
                Row(verticalAlignment = Alignment.CenterVertically) {
                    Icon(
                        imageVector = Icons.Outlined.Layers,
                        contentDescription = null,
                        tint = TecBlue,
                        modifier = Modifier.size(18.dp)
                    )
                    Spacer(modifier = Modifier.width(8.dp))
                    Text(
                        text = "Plano del campus",
                        color = Color(0xFF334155),
                        fontWeight = FontWeight.Medium
                    )
                }
            }
        }
    }
}
The simulated map displays:
  • Border frame: Light gray border representing the campus boundary
  • Building markers: Color-coded boxes for different building types
    • Blue for Edificio A (Classroom building)
    • Green for Lab 3 (Laboratory)
    • Orange for Cafetería (Cafeteria)
  • Current location: Gold circular marker showing user position
  • Map legend: Bottom-left label with layers icon

BuildingItem

List items for nearby buildings:
MapScreen.kt:324-386
@Composable
fun BuildingItem(
    title: String,
    subtitle: String,
    iconColor: Color
) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .clickable { },
        shape = RoundedCornerShape(22.dp),
        colors = CardDefaults.cardColors(containerColor = Color.White),
        elevation = CardDefaults.cardElevation(defaultElevation = 3.dp)
    ) {
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .padding(18.dp),
            verticalAlignment = Alignment.CenterVertically
        ) {
            Box(
                modifier = Modifier
                    .size(52.dp)
                    .background(iconColor.copy(alpha = 0.12f), CircleShape),
                contentAlignment = Alignment.Center
            ) {
                val icon = when {
                    title.contains("Lab") -> Icons.Outlined.Science
                    title.contains("Cafetería") -> Icons.Outlined.Coffee
                    else -> Icons.Outlined.Apartment
                }

                Icon(
                    imageVector = icon,
                    contentDescription = null,
                    tint = iconColor
                )
            }

            Spacer(modifier = Modifier.width(16.dp))

            Column(modifier = Modifier.weight(1f)) {
                Text(
                    text = title,
                    style = MaterialTheme.typography.titleLarge,
                    fontWeight = FontWeight.Bold,
                    color = Color(0xFF0F172A)
                )
                Spacer(modifier = Modifier.height(4.dp))
                Text(
                    text = subtitle,
                    style = MaterialTheme.typography.bodyLarge,
                    color = Color(0xFF64748B)
                )
            }

            Icon(
                imageVector = Icons.Outlined.LocationOn,
                contentDescription = "Ubicar",
                tint = TecBlue
            )
        }
    }
}
Each building card displays:
  • Icon: Dynamic icon based on building type (Apartment, Science, Coffee)
  • Title: Building name in bold
  • Subtitle: Description and distance (e.g., “Aulas generales · 120 m”)
  • Location indicator: Blue location pin icon on the right

My Location FAB

A floating action button to center the map on the user’s current location:
MapScreen.kt:57-68
floatingActionButton = {
    FloatingActionButton(
        onClick = { },
        containerColor = TecBlue,
        contentColor = Color.White,
        modifier = Modifier.navigationBarsPadding()
    ) {
        Icon(
            imageVector = Icons.Default.MyLocation,
            contentDescription = "Ubicación"
        )
    }
}

Sample Building Data

The app uses predefined building data:
FakeData.kt
val buildings = listOf(
    Building(
        id = 1,
        name = "Edificio A",
        description = "Aulas generales",
        category = "Aulas",
        distance = "120 m"
    ),
    Building(
        id = 2,
        name = "Laboratorio 3",
        description = "Prácticas de computación",
        category = "Labs",
        distance = "180 m"
    ),
    Building(
        id = 3,
        name = "Cafetería Central",
        description = "Zona de alimentos",
        category = "Cafetería",
        distance = "220 m"
    )
)

Screen Layout

MapScreen.kt:73-158
Column(
    modifier = Modifier
        .fillMaxSize()
        .padding(innerPadding)
        .verticalScroll(rememberScrollState())
) {
    MapHeader()

    Column(
        modifier = Modifier.padding(20.dp)
    ) {
        OutlinedTextField(...) // Search bar
        
        Spacer(modifier = Modifier.height(18.dp))
        
        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.spacedBy(10.dp)
        ) {
            FilterChipCustom("Todos", true)
            FilterChipCustom("Aulas", false)
            FilterChipCustom("Labs", false)
            FilterChipCustom("Cafetería", false)
        }
        
        Spacer(modifier = Modifier.height(20.dp))
        
        CampusMapCard()
        
        Spacer(modifier = Modifier.height(24.dp))
        
        Text(
            text = "Edificios cercanos",
            style = MaterialTheme.typography.headlineSmall,
            fontWeight = FontWeight.Bold,
            color = Color(0xFF0F172A)
        )
        
        Spacer(modifier = Modifier.height(14.dp))
        
        BuildingItem(...)
        BuildingItem(...)
        BuildingItem(...)
        
        Spacer(modifier = Modifier.height(90.dp))
    }
}

Key Features

Visual Map

Color-coded building markers on a simulated campus layout make it easy to understand the campus geography at a glance.

Search Functionality

Search bar allows students to quickly find specific buildings, classrooms, or facilities by name.

Category Filters

Filter buildings by type (All, Classrooms, Labs, Cafeteria) to narrow down results.

Distance Information

Each building card displays the distance from the user’s current location (e.g., “120 m”).

Building Categories

Aulas

General classroom buildings for lectures and courses

Labs

Laboratory buildings for hands-on practical work

Cafetería

Food service areas and student lounges

Current Implementation

The current version includes:
  • Simulated map visualization with positioned building markers
  • Static list of three sample buildings
  • Search input (UI only, no filtering logic)
  • Category filter chips (UI only, no filtering logic)
  • My Location FAB (UI only, no GPS integration)
The map is currently a static visualization. Tapping buildings or the location FAB does not trigger any functionality.

Future Enhancements

Real Map Integration

Integrate Google Maps or OpenStreetMap for a fully interactive, zoomable campus map.

GPS Navigation

Enable turn-by-turn navigation to guide students to their classrooms.

Live Search

Implement real-time filtering as users type in the search bar.

Building Details

Show detailed information about each building, including hours, accessibility, and amenities.

Schedule

View your classroom locations in your daily schedule

Home Screen

See current class location on the Home Screen