diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3eb5efb..0f4c973 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -59,7 +59,6 @@ dependencies { implementation(libs.androidx.ui.graphics) implementation(libs.androidx.ui.tooling.preview) implementation(libs.androidx.material3) - implementation(libs.androidx.appcompat) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) diff --git a/app/src/main/java/com/uniandes/ecobites/MainActivity.kt b/app/src/main/java/com/uniandes/ecobites/MainActivity.kt index 8dbf2ff..ae8359a 100644 --- a/app/src/main/java/com/uniandes/ecobites/MainActivity.kt +++ b/app/src/main/java/com/uniandes/ecobites/MainActivity.kt @@ -23,7 +23,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.example.ecobites.LoginScreen import com.uniandes.ecobites.ui.screens.CartScreen -import com.uniandes.ecobites.ui.screens.HomeScreen +import com.uniandes.ecobites.ui.screens.home.HomeScreen import com.uniandes.ecobites.ui.screens.ProfileScreen import com.uniandes.ecobites.ui.theme.AppTheme import com.uniandes.ecobites.ui.components.NavBar diff --git a/app/src/main/java/com/uniandes/ecobites/ui/navigation/NavigationHost.kt b/app/src/main/java/com/uniandes/ecobites/ui/navigation/NavigationHost.kt index cfeae9a..90d9de8 100644 --- a/app/src/main/java/com/uniandes/ecobites/ui/navigation/NavigationHost.kt +++ b/app/src/main/java/com/uniandes/ecobites/ui/navigation/NavigationHost.kt @@ -2,7 +2,7 @@ package com.uniandes.ecobites.ui.navigation import androidx.compose.runtime.Composable import com.uniandes.ecobites.ui.screens.CartScreen -import com.uniandes.ecobites.ui.screens.HomeScreen +import com.uniandes.ecobites.ui.screens.home.HomeScreen import com.uniandes.ecobites.ui.screens.OrdersScreen import com.uniandes.ecobites.ui.screens.ProfileScreen diff --git a/app/src/main/java/com/uniandes/ecobites/ui/screens/HomeScreen.kt b/app/src/main/java/com/uniandes/ecobites/ui/screens/HomeScreen.kt deleted file mode 100644 index b1be3c9..0000000 --- a/app/src/main/java/com/uniandes/ecobites/ui/screens/HomeScreen.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.uniandes.ecobites.ui.screens - -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable - -@Composable -fun HomeScreen() { - Text(text = "Home Screen") -} diff --git a/app/src/main/java/com/uniandes/ecobites/ui/screens/home/Carousel.kt b/app/src/main/java/com/uniandes/ecobites/ui/screens/home/Carousel.kt new file mode 100644 index 0000000..03df0f6 --- /dev/null +++ b/app/src/main/java/com/uniandes/ecobites/ui/screens/home/Carousel.kt @@ -0,0 +1,47 @@ +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.carousel.HorizontalMultiBrowseCarousel +import androidx.compose.material3.carousel.rememberCarouselState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import com.uniandes.ecobites.R + +@ExperimentalMaterial3Api +@Composable +fun OfferCarousel() { + // List of images to be shown in the carousel + val items = listOf( + R.drawable.percent, + R.drawable.free_delivery, + R.drawable.two_for_one, + R.drawable.fiftyoff + ) + + // Remember Carousel State + val carouselState = rememberCarouselState { items.size } + + // Carousel implementation using Hero Strategy + HorizontalMultiBrowseCarousel( + state = rememberCarouselState { items.count() }, + modifier = Modifier.height(250.dp).fillMaxWidth(), + preferredItemWidth = 250.dp, + itemSpacing = 8.dp, +// contentPadding = PaddingValues(horizontal = 40.dp) + ) { index -> + // Content of each carousel item + Image( + painter = painterResource(id = items[index]), + contentDescription = "Carousel Image", + contentScale = ContentScale.Crop, + modifier = Modifier + .height(300.dp).maskClip(MaterialTheme.shapes.extraLarge) + ) + } +} diff --git a/app/src/main/java/com/uniandes/ecobites/ui/screens/home/CategoriesRow.kt b/app/src/main/java/com/uniandes/ecobites/ui/screens/home/CategoriesRow.kt new file mode 100644 index 0000000..e6533c8 --- /dev/null +++ b/app/src/main/java/com/uniandes/ecobites/ui/screens/home/CategoriesRow.kt @@ -0,0 +1,62 @@ +import androidx.compose.foundation.layout.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Check +import androidx.compose.material.icons.rounded.Edit +import androidx.compose.material.icons.rounded.Home +import androidx.compose.material.icons.rounded.ShoppingCart +import androidx.compose.material.icons.rounded.Star +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp + +// Categories for the Tabs with Icons from Material Icons +data class Category(val name: String, val icon: ImageVector) + +val categories = listOf( + Category("Restaurant", Icons.Rounded.Home), + Category("Ingredients", Icons.Rounded.Edit), + Category("Store", Icons.Rounded.ShoppingCart), + Category("Diet", Icons.Rounded.Check) +) + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun CategoriesRow() { + var selectedTabIndex by remember { mutableStateOf(0) } + + ScrollableTabRow( + selectedTabIndex = selectedTabIndex, + modifier = Modifier.fillMaxWidth(), + containerColor = MaterialTheme.colorScheme.surface, + contentColor = MaterialTheme.colorScheme.onSurface, + edgePadding = 16.dp // Optional padding at the edges + ) { + categories.forEachIndexed { index, category -> + Tab( + selected = selectedTabIndex == index, + onClick = { selectedTabIndex = index }, + text = { + // Row to place the icon and text horizontally + Row( + verticalAlignment = androidx.compose.ui.Alignment.CenterVertically + ) { + Icon( + imageVector = category.icon, + contentDescription = "${category.name} Icon", + modifier = Modifier.size(20.dp) + ) + Spacer(modifier = Modifier.width(8.dp)) // Space between icon and text + Text( + text = category.name, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + } + ) + } + } +} diff --git a/app/src/main/java/com/uniandes/ecobites/ui/screens/home/HomeScreen.kt b/app/src/main/java/com/uniandes/ecobites/ui/screens/home/HomeScreen.kt new file mode 100644 index 0000000..48ae27a --- /dev/null +++ b/app/src/main/java/com/uniandes/ecobites/ui/screens/home/HomeScreen.kt @@ -0,0 +1,42 @@ +package com.uniandes.ecobites.ui.screens.home + +import StoresGrid +import CategoriesRow +import OfferCarousel +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun HomeScreen() { + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(16.dp) + ) { + // Top Location and Search Bar Section + TopSection() + + Spacer(modifier = Modifier.height(16.dp)) + +// Offer Carousel Section + OfferCarousel() + + Spacer(modifier = Modifier.height(16.dp)) + + // Categories Filter Section + CategoriesRow() + + Spacer(modifier = Modifier.height(16.dp)) + + // Stores/Restaurants Grid Section + StoresGrid() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/uniandes/ecobites/ui/screens/home/StoresGrid.kt b/app/src/main/java/com/uniandes/ecobites/ui/screens/home/StoresGrid.kt new file mode 100644 index 0000000..3bec7ad --- /dev/null +++ b/app/src/main/java/com/uniandes/ecobites/ui/screens/home/StoresGrid.kt @@ -0,0 +1,77 @@ +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.Alignment +import com.uniandes.ecobites.R + +// Data class representing a store +data class Store(val name: String, val imageResId: Int) + +// List of stores with their images +val stores = listOf( + Store("Éxito", R.drawable.exito), + Store("Hornitos", R.drawable.hornitos), + Store("McDonalds", R.drawable.mc_donalds), + Store("Dunkin Donuts", R.drawable.dunkin_donuts), + Store("Pan Pa' Ya!", R.drawable.pan_pa_ya) +) + +@Composable +fun StoresGrid() { + Column( + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + // First row with 2 items + Row( + horizontalArrangement = Arrangement.spacedBy(16.dp), + modifier = Modifier.fillMaxWidth() + ) { + stores.take(2).forEach { store -> + StoreItem(store = store, modifier = Modifier.weight(1f)) + } + } + + // Second row with 3 items + Row( + horizontalArrangement = Arrangement.spacedBy(16.dp), + modifier = Modifier.fillMaxWidth() + ) { + stores.drop(2).take(3).forEach { store -> + StoreItem(store = store, modifier = Modifier.weight(1f)) + } + } + } +} + +@Composable +fun StoreItem(store: Store, modifier: Modifier = Modifier) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = modifier + ) { + // Display the store image + Image( + painter = painterResource(id = store.imageResId), + contentDescription = store.name, + contentScale = ContentScale.Crop, + modifier = Modifier + .size(150.dp).clip(MaterialTheme.shapes.extraLarge) // Rounded corners for the image + ) + Spacer(modifier = Modifier.height(8.dp)) + + // Display the store name below the image + Text( + text = store.name, + style = MaterialTheme.typography.bodyMedium + ) + } +} diff --git a/app/src/main/java/com/uniandes/ecobites/ui/screens/home/TopSection.kt b/app/src/main/java/com/uniandes/ecobites/ui/screens/home/TopSection.kt new file mode 100644 index 0000000..764effe --- /dev/null +++ b/app/src/main/java/com/uniandes/ecobites/ui/screens/home/TopSection.kt @@ -0,0 +1,71 @@ +package com.uniandes.ecobites.ui.screens.home + +import androidx.compose.foundation.layout.* +import androidx.compose.material.icons.Icons +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.Alignment +import androidx.compose.material.icons.outlined.LocationOn +import androidx.compose.material.icons.outlined.Search +import androidx.compose.material.icons.outlined.Close +import androidx.compose.ui.unit.dp +import androidx.compose.ui.graphics.Color +import androidx.compose.material3.* +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.mutableStateOf +import androidx.compose.ui.tooling.preview.Preview + +// Top Section with Location and Search Bar +@Preview(showBackground = true) +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun TopSection() { + var query by remember { mutableStateOf("") } + var isActive by remember { mutableStateOf(false) } + + Column( + modifier = Modifier + .fillMaxWidth() + .padding(8.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + // Location Row + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + ) { + Icon(Icons.Outlined.LocationOn, contentDescription = "Location", tint = Color.Gray) + Spacer(modifier = Modifier.width(8.dp)) + Text(text = "Calle 13 #10-22", style = MaterialTheme.typography.bodyMedium) + } + Spacer(modifier = Modifier.height(8.dp)) + + // Material 3 Search Bar with Size Constraint + SearchBar( + query = query, + onQueryChange = { query = it }, + onSearch = { + // Handle search logic + }, + active = isActive, + onActiveChange = { isActive = it }, + placeholder = { Text("Search deals...") }, + leadingIcon = { Icon(Icons.Outlined.Search, contentDescription = "Search Icon") }, + trailingIcon = { + if (query.isNotEmpty()) { + IconButton(onClick = { query = "" }) { + Icon(Icons.Outlined.Close, contentDescription = "Clear") + } + } + }, + modifier = Modifier + .fillMaxWidth() // Ensure it fills the parent width properly + .heightIn(min = 56.dp, max = 72.dp) // Control the min and max height + .padding(horizontal = 8.dp) // Add some padding + ) { + // You can provide additional content here if needed + } + } +} diff --git a/app/src/main/res/drawable/dunkin_donuts.png b/app/src/main/res/drawable/dunkin_donuts.png new file mode 100644 index 0000000..8534783 Binary files /dev/null and b/app/src/main/res/drawable/dunkin_donuts.png differ diff --git a/app/src/main/res/drawable/exito.jpeg b/app/src/main/res/drawable/exito.jpeg new file mode 100644 index 0000000..85eb6a0 Binary files /dev/null and b/app/src/main/res/drawable/exito.jpeg differ diff --git a/app/src/main/res/drawable/fiftyoff.png b/app/src/main/res/drawable/fiftyoff.png new file mode 100644 index 0000000..5afd958 Binary files /dev/null and b/app/src/main/res/drawable/fiftyoff.png differ diff --git a/app/src/main/res/drawable/free_delivery.png b/app/src/main/res/drawable/free_delivery.png new file mode 100644 index 0000000..3413e6c Binary files /dev/null and b/app/src/main/res/drawable/free_delivery.png differ diff --git a/app/src/main/res/drawable/hornitos.jpeg b/app/src/main/res/drawable/hornitos.jpeg new file mode 100644 index 0000000..1fe0943 Binary files /dev/null and b/app/src/main/res/drawable/hornitos.jpeg differ diff --git a/app/src/main/res/drawable/mc_donalds.png b/app/src/main/res/drawable/mc_donalds.png new file mode 100644 index 0000000..44ef8ff Binary files /dev/null and b/app/src/main/res/drawable/mc_donalds.png differ diff --git a/app/src/main/res/drawable/pan_pa_ya.png b/app/src/main/res/drawable/pan_pa_ya.png new file mode 100644 index 0000000..6c6cae6 Binary files /dev/null and b/app/src/main/res/drawable/pan_pa_ya.png differ diff --git a/app/src/main/res/drawable/percent.png b/app/src/main/res/drawable/percent.png new file mode 100644 index 0000000..aa2cd1d Binary files /dev/null and b/app/src/main/res/drawable/percent.png differ diff --git a/app/src/main/res/drawable/two_for_one.png b/app/src/main/res/drawable/two_for_one.png new file mode 100644 index 0000000..620abf5 Binary files /dev/null and b/app/src/main/res/drawable/two_for_one.png differ diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c53bf58..e75a874 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,8 @@ espressoCore = "3.6.1" lifecycleRuntimeKtx = "2.8.5" activityCompose = "1.9.2" composeBom = "2024.04.01" -appcompat = "1.7.0" +composeVersion = "1.3.0" +runtimeAndroid = "1.7.2" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -24,8 +25,8 @@ androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } -androidx-material3 = { group = "androidx.compose.material3", name = "material3" } -androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } +androidx-material3 = { group = "androidx.compose.material3", name = "material3", version.ref="composeVersion" } +androidx-runtime-android = { group = "androidx.compose.runtime", name = "runtime-android", version.ref = "runtimeAndroid" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" }