package com.example.ui.admin import android.net.Uri import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.AddPhotoAlternate import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.Image import androidx.compose.material.icons.filled.PhotoLibrary import androidx.compose.material.icons.filled.Search import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.Checkbox import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.OutlinedButton import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Surface import androidx.compose.material3.Switch import androidx.compose.material3.SwitchDefaults import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.example.R import com.example.data.model.FoodItem import com.example.ui.components.FoodItemImage import com.example.ui.components.VegNonVegBadge import com.example.ui.theme.FreshVegGreen import com.example.ui.theme.LoveRedPrimary import com.example.ui.theme.TextPrimary import com.example.ui.theme.TextSecondary import com.example.viewmodel.AdminViewModel @Composable fun AdminMenuManagementScreen( adminViewModel: AdminViewModel, modifier: Modifier = Modifier ) { val items by adminViewModel.foodItems.collectAsState() var searchQuery by remember { mutableStateOf("") } var editingItem by remember { mutableStateOf(null) } var photoUpdateItem by remember { mutableStateOf(null) } var isAddingNewItem by remember { mutableStateOf(false) } val filtered = items.filter { searchQuery.isBlank() || it.name.contains(searchQuery, ignoreCase = true) || it.category.contains(searchQuery, ignoreCase = true) } Box(modifier = modifier.fillMaxSize()) { Column( modifier = Modifier .fillMaxSize() .padding(horizontal = 16.dp, vertical = 8.dp) ) { // Search & Add item bar Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(10.dp) ) { OutlinedTextField( value = searchQuery, onValueChange = { searchQuery = it }, placeholder = { Text("Search dishes in menu...", fontSize = 13.sp) }, leadingIcon = { Icon(Icons.Default.Search, contentDescription = null, tint = LoveRedPrimary) }, singleLine = true, shape = RoundedCornerShape(12.dp), colors = OutlinedTextFieldDefaults.colors( focusedTextColor = Color(0xFF1E2022), unfocusedTextColor = Color(0xFF1E2022), focusedContainerColor = Color.White, unfocusedContainerColor = Color(0xFFF8FAFC), cursorColor = LoveRedPrimary, focusedBorderColor = LoveRedPrimary, unfocusedBorderColor = Color(0xFFE2E8F0) ), modifier = Modifier.weight(1f).height(48.dp).testTag("admin_menu_search") ) Button( onClick = { isAddingNewItem = true }, shape = RoundedCornerShape(12.dp), colors = ButtonDefaults.buttonColors(containerColor = LoveRedPrimary), contentPadding = PaddingValues(horizontal = 12.dp, vertical = 8.dp), modifier = Modifier.height(48.dp).testTag("admin_add_new_dish_button") ) { Icon(Icons.Default.Add, contentDescription = null, modifier = Modifier.size(18.dp)) Spacer(modifier = Modifier.width(4.dp)) Text("Add Dish", fontWeight = FontWeight.Bold, fontSize = 13.sp) } } Spacer(modifier = Modifier.height(12.dp)) Text( text = "Total Dishes: ${items.size} | Tap picture icon to update food photo", fontSize = 11.sp, color = TextSecondary, fontWeight = FontWeight.Medium ) Spacer(modifier = Modifier.height(8.dp)) LazyColumn( modifier = Modifier.fillMaxSize(), contentPadding = PaddingValues(bottom = 72.dp), verticalArrangement = Arrangement.spacedBy(10.dp) ) { items(filtered) { item -> AdminFoodItemCard( item = item, onUpdatePhoto = { photoUpdateItem = item }, onEdit = { editingItem = item }, onToggleAvailability = { adminViewModel.toggleItemAvailability(item) }, onDelete = { adminViewModel.deleteFoodItem(item) } ) } } } } // Photo Update Dialog (CRITICAL REQUIREMENT: "add item logo update option available kardo taki ma apne hisab sa food ka pic da saku") photoUpdateItem?.let { item -> ItemPhotoUpdateDialog( item = item, onDismiss = { photoUpdateItem = null }, onUpdatePhoto = { newUri -> adminViewModel.updateItemImage(item.id, newUri) photoUpdateItem = null } ) } // Edit Item Dialog editingItem?.let { item -> DishEditDialog( initialItem = item, onDismiss = { editingItem = null }, onSave = { updated -> adminViewModel.saveFoodItem(updated) editingItem = null } ) } // Add New Item Dialog if (isAddingNewItem) { DishEditDialog( initialItem = FoodItem( name = "", category = "Biryani Special", price = 150.0, description = "Freshly prepared by Love Zone", isVeg = false, isAvailable = true ), isNew = true, onDismiss = { isAddingNewItem = false }, onSave = { newItem -> adminViewModel.saveFoodItem(newItem) isAddingNewItem = false } ) } } @Composable fun AdminFoodItemCard( item: FoodItem, onUpdatePhoto: () -> Unit, onEdit: () -> Unit, onToggleAvailability: () -> Unit, onDelete: () -> Unit ) { Card( shape = RoundedCornerShape(14.dp), colors = CardDefaults.cardColors(containerColor = Color.White), elevation = CardDefaults.cardElevation(defaultElevation = 1.dp), modifier = Modifier.fillMaxWidth().testTag("admin_item_${item.id}") ) { Row( modifier = Modifier.padding(12.dp), verticalAlignment = Alignment.CenterVertically ) { // Food photo with Change Photo Overlay button Box( modifier = Modifier .size(80.dp) .clip(RoundedCornerShape(10.dp)) .clickable(onClick = onUpdatePhoto) ) { FoodItemImage( imageUri = item.imageUri, contentDescription = item.name, modifier = Modifier.fillMaxSize() ) // Photo update hint overlay badge Box( modifier = Modifier .align(Alignment.BottomEnd) .background(Color.Black.copy(alpha = 0.7f), RoundedCornerShape(topStart = 8.dp)) .padding(4.dp) ) { Icon( imageVector = Icons.Default.AddPhotoAlternate, contentDescription = "Update photo", tint = Color.White, modifier = Modifier.size(16.dp) ) } VegNonVegBadge( isVeg = item.isVeg, modifier = Modifier.align(Alignment.TopStart).padding(4.dp) ) } Spacer(modifier = Modifier.width(12.dp)) Column(modifier = Modifier.weight(1f)) { Text( text = item.name, fontWeight = FontWeight.Bold, fontSize = 14.sp, color = TextPrimary, maxLines = 1, overflow = TextOverflow.Ellipsis ) Text( text = "${item.category} • ₹${item.price.toInt()}", fontSize = 12.sp, fontWeight = FontWeight.SemiBold, color = LoveRedPrimary ) Spacer(modifier = Modifier.height(4.dp)) Row(verticalAlignment = Alignment.CenterVertically) { Text( text = if (item.isAvailable) "In Stock" else "Sold Out", fontSize = 11.sp, color = if (item.isAvailable) FreshVegGreen else Color.Red, fontWeight = FontWeight.Bold ) Spacer(modifier = Modifier.width(6.dp)) Switch( checked = item.isAvailable, onCheckedChange = { onToggleAvailability() }, colors = SwitchDefaults.colors( checkedThumbColor = Color.White, checkedTrackColor = FreshVegGreen ), modifier = Modifier.size(width = 38.dp, height = 24.dp) ) } } Row(verticalAlignment = Alignment.CenterVertically) { IconButton(onClick = onUpdatePhoto) { Icon(Icons.Default.AddPhotoAlternate, contentDescription = "Change Picture", tint = LoveRedPrimary) } IconButton(onClick = onEdit) { Icon(Icons.Default.Edit, contentDescription = "Edit", tint = Color.Gray) } IconButton(onClick = onDelete) { Icon(Icons.Default.Delete, contentDescription = "Delete", tint = Color.Gray) } } } } } @Composable fun ItemPhotoUpdateDialog( item: FoodItem, onDismiss: () -> Unit, onUpdatePhoto: (String) -> Unit ) { var customUriText by remember { mutableStateOf(item.imageUri) } // Android System Photo Picker (Zero-permission photo picker!) val photoPickerLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.PickVisualMedia() ) { uri: Uri? -> if (uri != null) { customUriText = uri.toString() onUpdatePhoto(uri.toString()) } } val presetImages = listOf( "img_special_biryani" to "Royal Dum Biryani", "img_food_banner" to "Special Feast Platter", "logo_love_zone" to "Love Zone Official Logo" ) AlertDialog( onDismissRequest = onDismiss, title = { Column { Text(text = "Update Food Picture", fontWeight = FontWeight.Bold, fontSize = 16.sp) Text(text = item.name, fontSize = 12.sp, color = TextSecondary) } }, text = { Column( modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(12.dp) ) { Text( text = "Pick a custom food photo from your gallery or choose a preset photo:", fontSize = 12.sp, color = TextSecondary ) // Pick from Gallery Button Button( onClick = { photoPickerLauncher.launch( androidx.activity.result.PickVisualMediaRequest( ActivityResultContracts.PickVisualMedia.ImageOnly ) ) }, shape = RoundedCornerShape(10.dp), colors = ButtonDefaults.buttonColors(containerColor = LoveRedPrimary), modifier = Modifier.fillMaxWidth().testTag("pick_from_gallery_button") ) { Icon(Icons.Default.PhotoLibrary, contentDescription = null, modifier = Modifier.size(18.dp)) Spacer(modifier = Modifier.width(8.dp)) Text("Select Photo from Gallery", fontWeight = FontWeight.Bold, fontSize = 13.sp) } HorizontalDivider(color = Color(0xFFF1F5F9)) Text(text = "Or Select Delicious Presets:", fontWeight = FontWeight.SemiBold, fontSize = 12.sp) for ((resName, label) in presetImages) { Surface( color = if (customUriText == resName) Color(0xFFFFF1F2) else Color(0xFFF8FAFC), shape = RoundedCornerShape(10.dp), border = androidx.compose.foundation.BorderStroke( 1.dp, if (customUriText == resName) LoveRedPrimary else Color(0xFFE2E8F0) ), modifier = Modifier .fillMaxWidth() .clickable { customUriText = resName onUpdatePhoto(resName) } ) { Row( modifier = Modifier.padding(10.dp), verticalAlignment = Alignment.CenterVertically ) { Box( modifier = Modifier .size(40.dp) .clip(RoundedCornerShape(6.dp)) ) { FoodItemImage( imageUri = resName, contentDescription = label, modifier = Modifier.fillMaxSize() ) } Spacer(modifier = Modifier.width(10.dp)) Text(text = label, fontSize = 13.sp, fontWeight = FontWeight.Medium, color = TextPrimary) Spacer(modifier = Modifier.weight(1f)) if (customUriText == resName) { Icon(Icons.Default.Check, contentDescription = null, tint = LoveRedPrimary, modifier = Modifier.size(18.dp)) } } } } // Custom URL/URI input OutlinedTextField( value = customUriText, onValueChange = { customUriText = it }, label = { Text("Image URL or Path") }, singleLine = true, shape = RoundedCornerShape(10.dp), colors = OutlinedTextFieldDefaults.colors( focusedTextColor = Color(0xFF1E2022), unfocusedTextColor = Color(0xFF1E2022), focusedContainerColor = Color.White, unfocusedContainerColor = Color(0xFFF8FAFC), cursorColor = LoveRedPrimary, focusedBorderColor = LoveRedPrimary, unfocusedBorderColor = Color(0xFFCBD5E1) ), modifier = Modifier.fillMaxWidth().testTag("image_url_input") ) } }, confirmButton = { Button( onClick = { onUpdatePhoto(customUriText) }, colors = ButtonDefaults.buttonColors(containerColor = LoveRedPrimary), modifier = Modifier.testTag("confirm_photo_update_button") ) { Text("Save Photo") } }, dismissButton = { TextButton(onClick = onDismiss) { Text("Cancel", color = TextSecondary) } } ) } @Composable fun DishEditDialog( initialItem: FoodItem, isNew: Boolean = false, onDismiss: () -> Unit, onSave: (FoodItem) -> Unit ) { var name by remember { mutableStateOf(initialItem.name) } var category by remember { mutableStateOf(initialItem.category) } var priceStr by remember { mutableStateOf(initialItem.price.toInt().toString()) } var description by remember { mutableStateOf(initialItem.description) } var isVeg by remember { mutableStateOf(initialItem.isVeg) } var isBestSeller by remember { mutableStateOf(initialItem.isBestSeller) } val categories = listOf( "Love Zone Special Combos", "Rice & Biryani", "Tandoor & Roti", "Starters & Snacks", "Main Course", "Noodles & Momos", "Pizza, Burgers & Rolls", "Beverages & Shakes" ) AlertDialog( onDismissRequest = onDismiss, title = { Text(if (isNew) "Add New Dish" else "Edit Dish Details", fontWeight = FontWeight.Bold) }, text = { Column( modifier = Modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(10.dp) ) { OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Dish Name") }, singleLine = true, shape = RoundedCornerShape(10.dp), colors = OutlinedTextFieldDefaults.colors( focusedTextColor = Color(0xFF1E2022), unfocusedTextColor = Color(0xFF1E2022), focusedContainerColor = Color.White, unfocusedContainerColor = Color(0xFFF8FAFC), cursorColor = LoveRedPrimary, focusedBorderColor = LoveRedPrimary, unfocusedBorderColor = Color(0xFFCBD5E1) ), modifier = Modifier.fillMaxWidth().testTag("dish_name_input") ) OutlinedTextField( value = priceStr, onValueChange = { priceStr = it }, label = { Text("Price (₹)") }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), singleLine = true, shape = RoundedCornerShape(10.dp), colors = OutlinedTextFieldDefaults.colors( focusedTextColor = Color(0xFF1E2022), unfocusedTextColor = Color(0xFF1E2022), focusedContainerColor = Color.White, unfocusedContainerColor = Color(0xFFF8FAFC), cursorColor = LoveRedPrimary, focusedBorderColor = LoveRedPrimary, unfocusedBorderColor = Color(0xFFCBD5E1) ), modifier = Modifier.fillMaxWidth().testTag("dish_price_input") ) Text(text = "Category:", fontSize = 12.sp, fontWeight = FontWeight.SemiBold) Row( modifier = Modifier.fillMaxWidth().horizontalScroll(rememberScrollState()), horizontalArrangement = Arrangement.spacedBy(6.dp) ) { for (cat in categories) { Surface( color = if (category == cat) LoveRedPrimary else Color(0xFFF1F5F9), shape = RoundedCornerShape(12.dp), modifier = Modifier.clickable { category = cat } ) { Text( text = cat, color = if (category == cat) Color.White else TextPrimary, fontSize = 11.sp, fontWeight = FontWeight.Medium, modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp) ) } } } OutlinedTextField( value = description, onValueChange = { description = it }, label = { Text("Description") }, maxLines = 2, shape = RoundedCornerShape(10.dp), colors = OutlinedTextFieldDefaults.colors( focusedTextColor = Color(0xFF1E2022), unfocusedTextColor = Color(0xFF1E2022), focusedContainerColor = Color.White, unfocusedContainerColor = Color(0xFFF8FAFC), cursorColor = LoveRedPrimary, focusedBorderColor = LoveRedPrimary, unfocusedBorderColor = Color(0xFFCBD5E1) ), modifier = Modifier.fillMaxWidth() ) Row(verticalAlignment = Alignment.CenterVertically) { Checkbox(checked = isVeg, onCheckedChange = { isVeg = it }) Text(text = "Pure Vegetarian", fontSize = 13.sp) } Row(verticalAlignment = Alignment.CenterVertically) { Checkbox(checked = isBestSeller, onCheckedChange = { isBestSeller = it }) Text(text = "Mark as Trending / Best Seller", fontSize = 13.sp) } } }, confirmButton = { Button( onClick = { val price = priceStr.toDoubleOrNull() ?: initialItem.price val updated = initialItem.copy( name = name.ifBlank { "New Dish" }, category = category, price = price, description = description, isVeg = isVeg, isBestSeller = isBestSeller ) onSave(updated) }, colors = ButtonDefaults.buttonColors(containerColor = LoveRedPrimary), modifier = Modifier.testTag("save_dish_button") ) { Text("Save") } }, dismissButton = { TextButton(onClick = onDismiss) { Text("Cancel", color = TextSecondary) } } ) }