diff --git a/demo-app/build.gradle.kts b/demo-app/build.gradle.kts index 75b3eeaca..1f2f1f20e 100644 --- a/demo-app/build.gradle.kts +++ b/demo-app/build.gradle.kts @@ -65,6 +65,7 @@ dependencies { implementation(libs.androidx.navigation.fragment.ktx) implementation(libs.androidx.navigation.ui.ktx) implementation(libs.opentelemetry.api.incubator) + implementation(libs.androidx.navigation.compose) coreLibraryDesugaring(libs.desugarJdkLibs) diff --git a/demo-app/gradle/libs.versions.toml b/demo-app/gradle/libs.versions.toml index ea8041f42..8786f1288 100644 --- a/demo-app/gradle/libs.versions.toml +++ b/demo-app/gradle/libs.versions.toml @@ -4,6 +4,7 @@ opentelemetry-alpha = "1.39.0-alpha" junit = "5.10.3" spotless = "6.25.0" kotlin = "2.0.0" +navigation-compose = "2.7.7" [libraries] androidx-appcompat = "androidx.appcompat:appcompat:1.7.0" @@ -35,8 +36,9 @@ androidx-constraintlayout = { group = "androidx.constraintlayout", name = "const material = { group = "com.google.android.material", name = "material", version = "1.12.0" } androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version = "2.8.4" } androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version = "2.8.4" } -androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version = "2.7.7" } -androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version = "2.7.7" } +androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigation-compose" } +androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigation-compose" } +androidx-navigation-compose = {group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation-compose"} [bundles] junit = ["junit-jupiter-api", "junit-jupiter-engine", "junit-vintage-engine"] diff --git a/demo-app/src/main/AndroidManifest.xml b/demo-app/src/main/AndroidManifest.xml index c04a07e76..1046456dd 100644 --- a/demo-app/src/main/AndroidManifest.xml +++ b/demo-app/src/main/AndroidManifest.xml @@ -18,7 +18,7 @@ android:usesCleartextTraffic="true" tools:targetApi="31"> diff --git a/demo-app/src/main/java/io/opentelemetry/android/demo/AstronomyShopActivity.kt b/demo-app/src/main/java/io/opentelemetry/android/demo/AstronomyShopActivity.kt deleted file mode 100644 index f031cb71b..000000000 --- a/demo-app/src/main/java/io/opentelemetry/android/demo/AstronomyShopActivity.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.android.demo - -import android.content.Intent -import android.os.Bundle -import android.util.Log -import android.view.MenuItem -import androidx.appcompat.app.AppCompatActivity -import androidx.navigation.findNavController -import androidx.navigation.ui.AppBarConfiguration -import androidx.navigation.ui.setupActionBarWithNavController -import androidx.navigation.ui.setupWithNavController -import com.google.android.material.bottomnavigation.BottomNavigationView -import io.opentelemetry.android.demo.databinding.ActivityAstronomyShopBinding - -class AstronomyShopActivity : AppCompatActivity() { - private lateinit var binding: ActivityAstronomyShopBinding - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - binding = ActivityAstronomyShopBinding.inflate(layoutInflater) - setContentView(binding.root) - - val navView: BottomNavigationView = binding.navView - - val navController = findNavController(R.id.nav_host_fragment_activity_astronomy_shop) - // Passing each menu ID as a set of Ids because each - // menu should be considered as top level destinations. - val appBarConfiguration = - AppBarConfiguration( - setOf( - R.id.navigation_home, - R.id.navigation_dashboard, - R.id.navigation_cart, - ), - ) - setupActionBarWithNavController(navController, appBarConfiguration) - navView.setupWithNavController(navController) - } - - fun onExitToMainClicked(item: MenuItem) { - Log.d(TAG, "Exiting shop back to main activity") - startActivity(Intent(this@AstronomyShopActivity, MainActivity::class.java)) - } -} diff --git a/demo-app/src/main/java/io/opentelemetry/android/demo/MainActivity.kt b/demo-app/src/main/java/io/opentelemetry/android/demo/MainActivity.kt index 96ee2730d..6e5c2a36e 100644 --- a/demo-app/src/main/java/io/opentelemetry/android/demo/MainActivity.kt +++ b/demo-app/src/main/java/io/opentelemetry/android/demo/MainActivity.kt @@ -29,6 +29,7 @@ import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import io.opentelemetry.android.demo.theme.DemoAppTheme +import io.opentelemetry.android.demo.ui.shop.AstronomyShopActivity class MainActivity : ComponentActivity() { private val viewModel by viewModels() diff --git a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/cart/CartFragment.kt b/demo-app/src/main/java/io/opentelemetry/android/demo/ui/cart/CartFragment.kt deleted file mode 100644 index 2e039c40c..000000000 --- a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/cart/CartFragment.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.android.demo.ui.cart - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProvider -import io.opentelemetry.android.demo.databinding.FragmentNotificationsBinding - -class CartFragment : Fragment() { - // Renamed from _binding (default) due to ktlint problem below - private var binding: FragmentNotificationsBinding? = null - - // This property is only valid between onCreateView and onDestroyView. - // Currently failing ktlint due to - // https://github.com/pinterest/ktlint/issues/2448 - // which hasn't hit the aging gradle spotless plugin yet -// private val binding get() = _binding!! - private fun getBinding(): FragmentNotificationsBinding { - return binding!! - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - val cartViewModel = - ViewModelProvider(this).get(CartViewModel::class.java) - - binding = FragmentNotificationsBinding.inflate(inflater, container, false) - val root: View = getBinding().root - - val textView: TextView = getBinding().textNotifications - cartViewModel.text.observe(viewLifecycleOwner) { - textView.text = it - } - return root - } - - override fun onDestroyView() { - super.onDestroyView() - binding = null - } -} diff --git a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/cart/CartViewModel.kt b/demo-app/src/main/java/io/opentelemetry/android/demo/ui/cart/CartViewModel.kt deleted file mode 100644 index b2c5a207b..000000000 --- a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/cart/CartViewModel.kt +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.android.demo.ui.cart - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel - -class CartViewModel : ViewModel() { - private val _text = - MutableLiveData().apply { - value = "This is cart Fragment" - } - val text: LiveData = _text -} diff --git a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/dashboard/DashboardFragment.kt b/demo-app/src/main/java/io/opentelemetry/android/demo/ui/dashboard/DashboardFragment.kt deleted file mode 100644 index 9a4481934..000000000 --- a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/dashboard/DashboardFragment.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.android.demo.ui.dashboard - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProvider -import io.opentelemetry.android.demo.databinding.FragmentDashboardBinding - -class DashboardFragment : Fragment() { - // Renamed from _binding (default) due to ktlint problem below - private var binding: FragmentDashboardBinding? = null - - // This property is only valid between onCreateView and onDestroyView. - // Currently failing ktlint due to - // https://github.com/pinterest/ktlint/issues/2448 - // which hasn't hit the aging gradle spotless plugin yet -// private val binding get() = _binding!! - fun getBinding(): FragmentDashboardBinding { - return binding!! - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - val dashboardViewModel = - ViewModelProvider(this).get(DashboardViewModel::class.java) - - binding = FragmentDashboardBinding.inflate(inflater, container, false) - val root: View = getBinding().root - - val textView: TextView = getBinding().textDashboard - dashboardViewModel.text.observe(viewLifecycleOwner) { - textView.text = it - } - return root - } - - override fun onDestroyView() { - super.onDestroyView() - binding = null - } -} diff --git a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/dashboard/DashboardViewModel.kt b/demo-app/src/main/java/io/opentelemetry/android/demo/ui/dashboard/DashboardViewModel.kt deleted file mode 100644 index af4464db2..000000000 --- a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/dashboard/DashboardViewModel.kt +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.android.demo.ui.dashboard - -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel - -class DashboardViewModel : ViewModel() { - private val _text = - MutableLiveData().apply { - value = "This is dashboard Fragment" - } - val text: LiveData = _text -} diff --git a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/AstronomyShopActivity.kt b/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/AstronomyShopActivity.kt new file mode 100644 index 000000000..feb6edee1 --- /dev/null +++ b/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/AstronomyShopActivity.kt @@ -0,0 +1,95 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.android.demo.ui.shop + +import android.app.Activity +import android.content.Intent +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.appcompat.app.AppCompatActivity +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import io.opentelemetry.android.demo.MainActivity +import io.opentelemetry.android.demo.clients.ProductCatalogClient +import io.opentelemetry.android.demo.theme.DemoAppTheme +import io.opentelemetry.android.demo.ui.shop.cart.CartScreen +import io.opentelemetry.android.demo.ui.shop.products.ProductDetails +import io.opentelemetry.android.demo.ui.shop.products.ProductList + +class AstronomyShopActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + AstronomyShopScreen() + } + } +} + +@Composable +fun AstronomyShopScreen() { + val productsClient = ProductCatalogClient(LocalContext.current) + val products by remember { mutableStateOf(productsClient.get()) } + val context = LocalContext.current + val astronomyShopNavController = rememberAstronomyShopNavController() + + DemoAppTheme { + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + Scaffold( + bottomBar = { + BottomNavigationBar( + items = listOf(BottomNavItem.Exit, BottomNavItem.List, BottomNavItem.Cart), + currentRoute = astronomyShopNavController.currentRoute, + onItemClicked = { route -> + astronomyShopNavController.navController.navigate(route) { + popUpTo(astronomyShopNavController.navController.graph.startDestinationId) + launchSingleTop = true + } + }, + onExitClicked = { + val intent = Intent(context, MainActivity::class.java) + context.startActivity(intent) + (context as? Activity)?.finish() + } + ) + } + ) { innerPadding -> + NavHost( + navController = astronomyShopNavController.navController, + startDestination = MainDestinations.HOME_ROUTE, + Modifier.padding(innerPadding) + ) { + composable(BottomNavItem.List.route) { + ProductList(products = products) { productId -> + astronomyShopNavController.navigateToProductDetail(productId) + } + } + composable(BottomNavItem.Cart.route) { + CartScreen() + } + composable("${MainDestinations.PRODUCT_DETAIL_ROUTE}/{${MainDestinations.PRODUCT_ID_KEY}}") { backStackEntry -> + val productId = backStackEntry.arguments?.getString(MainDestinations.PRODUCT_ID_KEY) + val product = products.find { it.id == productId } + product?.let { ProductDetails(product = it) } + } + } + } + } + } +} diff --git a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/Navigation.kt b/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/Navigation.kt new file mode 100644 index 000000000..76942e2e8 --- /dev/null +++ b/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/Navigation.kt @@ -0,0 +1,80 @@ +package io.opentelemetry.android.demo.ui.shop + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ExitToApp +import androidx.compose.material.icons.automirrored.filled.List +import androidx.compose.material.icons.filled.ShoppingCart +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.remember +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.lifecycle.Lifecycle +import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavDestination +import androidx.navigation.NavGraph +import androidx.navigation.NavHostController +import androidx.navigation.compose.rememberNavController +import androidx.compose.material3.* + + +sealed class BottomNavItem(val route: String, val icon: ImageVector, val label: String) { + data object Exit : BottomNavItem("home", Icons.AutoMirrored.Filled.ExitToApp, "Exit") + data object List : BottomNavItem("prod-list", Icons.AutoMirrored.Filled.List, "List") + data object Cart : BottomNavItem("cart", Icons.Filled.ShoppingCart, "Cart") +} + +object MainDestinations { + const val HOME_ROUTE = "prod-list" + const val PRODUCT_DETAIL_ROUTE = "product" + const val PRODUCT_ID_KEY = "productId" +} + +@Composable +fun rememberAstronomyShopNavController(navController: NavHostController = rememberNavController()) +: AstronomyShopNavController = remember(navController) +{ + AstronomyShopNavController(navController) +} + +@Stable +class AstronomyShopNavController( + val navController: NavHostController, +) { + val currentRoute: String? + get() = navController.currentDestination?.route + + fun upPress() { + navController.navigateUp() + } + + fun navigateToProductDetail(productId: String) { + navController.navigate("${MainDestinations.PRODUCT_DETAIL_ROUTE}/$productId") + } + +} + +@Composable +fun BottomNavigationBar( + items: List, + currentRoute: String?, + onItemClicked: (String) -> Unit, + onExitClicked: () -> Unit +) { + NavigationBar { + items.forEach { item -> + NavigationBarItem( + selected = currentRoute == item.route, + onClick = { + if (item.route == BottomNavItem.Exit.route) { + onExitClicked() + } else { + onItemClicked(item.route) + } + }, + icon = { Icon(item.icon, contentDescription = item.label) }, + label = { Text(item.label) } + ) + } + } +} \ No newline at end of file diff --git a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/ShopFragment.kt b/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/ShopFragment.kt deleted file mode 100644 index b5ea4294c..000000000 --- a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/ShopFragment.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.android.demo.ui.shop - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.runtime.mutableStateOf -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.ComposeView -import androidx.fragment.app.Fragment -import io.opentelemetry.android.demo.clients.ProductCatalogClient -import io.opentelemetry.android.demo.theme.DemoAppTheme - -class ShopFragment : Fragment() { - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - - val productsClient = ProductCatalogClient(requireContext()) - val products = productsClient.get() - val productState = mutableStateOf(products) - - return ComposeView(requireContext()).apply { - setContent { - DemoAppTheme { - // A surface container using the 'background' color from the theme - Surface( - modifier = Modifier.fillMaxSize(), - color = MaterialTheme.colorScheme.background, - ) { - ProductList(productState) - } - } - } - } - } - -} diff --git a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/cart/Cart.kt b/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/cart/Cart.kt new file mode 100644 index 000000000..a0781e841 --- /dev/null +++ b/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/cart/Cart.kt @@ -0,0 +1,62 @@ +package io.opentelemetry.android.demo.ui.shop.cart + +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import io.opentelemetry.android.demo.model.Product + + +@Composable +fun CartScreen() { + val products : List = listOf() + Scaffold( + content = { innerPadding -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(innerPadding), + verticalArrangement = Arrangement.SpaceBetween + ) { + LazyColumn( + modifier = Modifier.weight(1f) + ) { + items(products.size) { index -> CartItem(products[index]) } + } + CheckoutButton(totalPrice = products.sumOf { it.priceValue() }) + } + } + ) +} + +@Composable +fun CartItem(product: Product) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 8.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text(text = product.name, fontSize = 20.sp) + Text(text = "$${product.priceUsd}", fontSize = 20.sp) + } +} + +@Composable +fun CheckoutButton(totalPrice: Double) { + Button( + onClick = { /* TODO: Add checkout logic */ }, + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 16.dp) + ) { + Text(text = "Checkout ($${String.format("%.2f", totalPrice)})") + } +} \ No newline at end of file diff --git a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/ProductCard.kt b/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/products/ProductCard.kt similarity index 72% rename from demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/ProductCard.kt rename to demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/products/ProductCard.kt index 0da990da4..e5100efa9 100644 --- a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/ProductCard.kt +++ b/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/products/ProductCard.kt @@ -1,7 +1,6 @@ -package io.opentelemetry.android.demo.ui.shop +package io.opentelemetry.android.demo.ui.shop.products import android.graphics.Bitmap -import android.util.Log import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -15,7 +14,6 @@ import androidx.compose.material3.CardColors import androidx.compose.material3.CardDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.asImageBitmap @@ -24,33 +22,33 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import io.opentelemetry.android.demo.TAG import io.opentelemetry.android.demo.clients.ImageLoader import io.opentelemetry.android.demo.gothamFont import io.opentelemetry.android.demo.model.Product @Composable -fun ProductCard(product: Product) { +fun ProductCard(product: Product, onClick: (String) -> Unit) { val imageLoader = ImageLoader(LocalContext.current) val sourceProductImage = imageLoader.load(product.picture) Bitmap.createScaledBitmap(sourceProductImage, 120, 120, false) -// Bitmap.createBitmap() val cardColors = CardColors( containerColor = Color.White, contentColor = Color.Black, disabledContentColor = Color.Black, disabledContainerColor = Color.Black ) - Card(elevation = CardDefaults.cardElevation(defaultElevation = 10.dp), + Card( + elevation = CardDefaults.cardElevation(defaultElevation = 10.dp), colors = cardColors, - modifier = Modifier.fillMaxSize() - .height(200.dp) - .wrapContentHeight() - .padding(20.dp), - onClick = { - Log.d(TAG, "TODO: Implement me!") - } + modifier = Modifier + .fillMaxSize() + .height(200.dp) + .wrapContentHeight() + .padding(20.dp), + onClick = { onClick(product.id) } ) { - Row(modifier = Modifier.fillMaxSize().padding(20.dp)) { + Row(modifier = Modifier + .fillMaxSize() + .padding(20.dp)) { Row(modifier = Modifier.fillMaxWidth()) { Column { Image( @@ -59,14 +57,17 @@ fun ProductCard(product: Product) { ) } Column(modifier = Modifier.fillMaxWidth()) { - Text(product.name + "\n\n$" + product.priceValue(), fontFamily = gothamFont, + Text( + product.name + "\n\n$" + product.priceValue(), + fontFamily = gothamFont, style = TextStyle.Default.copy(textAlign = TextAlign.Right), fontSize = 18.sp, - modifier = Modifier.padding(start = 15.dp, top = 25.dp).fillMaxWidth() + modifier = Modifier + .padding(start = 15.dp, top = 25.dp) + .fillMaxWidth() ) - } } } } -} \ No newline at end of file +} diff --git a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/products/ProductDetails.kt b/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/products/ProductDetails.kt new file mode 100644 index 000000000..5b0a30e20 --- /dev/null +++ b/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/products/ProductDetails.kt @@ -0,0 +1,73 @@ +package io.opentelemetry.android.demo.ui.shop.products + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import io.opentelemetry.android.demo.clients.ImageLoader +import io.opentelemetry.android.demo.gothamFont +import io.opentelemetry.android.demo.model.Product + +@Composable +fun ProductDetails(product:Product){ + val imageLoader = ImageLoader(LocalContext.current) + val sourceProductImage = imageLoader.load(product.picture) + + Column( + modifier = Modifier + .fillMaxSize() + .padding(16.dp) + .verticalScroll(rememberScrollState()) + ) { + Image( + bitmap = sourceProductImage.asImageBitmap(), + contentDescription = product.name, + modifier = Modifier + .fillMaxWidth() + .height(300.dp) + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = product.name, + fontFamily = gothamFont, + fontSize = 24.sp, + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Center + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = product.description, + color = Color.Gray, + textAlign = TextAlign.Justify, + fontFamily = gothamFont, + fontSize = 16.sp, + modifier = Modifier.fillMaxWidth() + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = "$${product.priceValue()}", + fontFamily = gothamFont, + fontSize = 24.sp, + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Center + ) + Spacer(modifier = Modifier.height(32.dp)) + Button( + onClick = { /* TODO: Handle add to cart */ }, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + ) { + Text(text = "Add to Cart") + } + } +} diff --git a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/ProductList.kt b/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/products/ProductList.kt similarity index 69% rename from demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/ProductList.kt rename to demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/products/ProductList.kt index 04de9d82e..8c26bd1f9 100644 --- a/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/ProductList.kt +++ b/demo-app/src/main/java/io/opentelemetry/android/demo/ui/shop/products/ProductList.kt @@ -1,4 +1,4 @@ -package io.opentelemetry.android.demo.ui.shop +package io.opentelemetry.android.demo.ui.shop.products import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row @@ -6,17 +6,16 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.runtime.Composable -import androidx.compose.runtime.State import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import io.opentelemetry.android.demo.model.Product @Composable -fun ProductList(products: State>) { +fun ProductList(products: List, onProductClick: (String) -> Unit) { LazyColumn(modifier = Modifier.fillMaxSize()) { - items(products.value.size) { index -> - Row() { - ProductCard(products.value[index]) + items(products.size) { index -> + Row { + ProductCard(products[index], onClick = onProductClick) } } item { @@ -25,4 +24,4 @@ fun ProductList(products: State>) { ) } } -} \ No newline at end of file +} diff --git a/demo-app/src/main/res/layout/activity_astronomy_shop.xml b/demo-app/src/main/res/layout/activity_astronomy_shop.xml index 87f9dba2c..cd1f2df91 100644 --- a/demo-app/src/main/res/layout/activity_astronomy_shop.xml +++ b/demo-app/src/main/res/layout/activity_astronomy_shop.xml @@ -4,30 +4,4 @@ android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingTop="?attr/actionBarSize"> - - - - - - \ No newline at end of file + android:paddingTop="?attr/actionBarSize"/> \ No newline at end of file diff --git a/demo-app/src/main/res/layout/fragment_dashboard.xml b/demo-app/src/main/res/layout/fragment_dashboard.xml deleted file mode 100644 index 166ab0e9e..000000000 --- a/demo-app/src/main/res/layout/fragment_dashboard.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - \ No newline at end of file diff --git a/demo-app/src/main/res/layout/fragment_home.xml b/demo-app/src/main/res/layout/fragment_home.xml deleted file mode 100644 index 5778483d8..000000000 --- a/demo-app/src/main/res/layout/fragment_home.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - \ No newline at end of file diff --git a/demo-app/src/main/res/navigation/mobile_navigation.xml b/demo-app/src/main/res/navigation/mobile_navigation.xml deleted file mode 100644 index da4972c97..000000000 --- a/demo-app/src/main/res/navigation/mobile_navigation.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - \ No newline at end of file