diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index 2e03d9b..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -LivingAi_Lg \ No newline at end of file diff --git a/app/src/main/java/com/example/livingai_lg/api/AuthApiClient.kt b/app/src/main/java/com/example/livingai_lg/api/AuthApiClient.kt index cb0db25..05df18c 100644 --- a/app/src/main/java/com/example/livingai_lg/api/AuthApiClient.kt +++ b/app/src/main/java/com/example/livingai_lg/api/AuthApiClient.kt @@ -27,6 +27,7 @@ class UserNotFoundException( class AuthApiClient(private val context: Context) { + private val route = "http://10.0.2.2:3000/" private val tokenManager = TokenManager(context) val client = HttpClient(CIO) { @@ -64,7 +65,7 @@ class AuthApiClient(private val context: Context) { android.util.Log.d("AuthApiClient", "refreshTokens: Calling /auth/refresh endpoint") try { - val response: RefreshResponse = client.post("http://10.0.2.2:3000/auth/refresh") { + val response: RefreshResponse = client.post("${route}auth/refresh") { markAsRefreshTokenRequest() contentType(ContentType.Application.Json) setBody(RefreshRequest(refreshToken)) @@ -84,7 +85,7 @@ class AuthApiClient(private val context: Context) { } defaultRequest { - url("http://10.0.2.2:3000/") + url(route) } } diff --git a/app/src/main/java/com/example/livingai_lg/ui/components/AnimalTypeSelector.kt b/app/src/main/java/com/example/livingai_lg/ui/components/AnimalTypeSelector.kt index ad930c7..e4153ec 100644 --- a/app/src/main/java/com/example/livingai_lg/ui/components/AnimalTypeSelector.kt +++ b/app/src/main/java/com/example/livingai_lg/ui/components/AnimalTypeSelector.kt @@ -1,87 +1,87 @@ -package com.example.livingai_lg.ui.components - -import androidx.compose.foundation.LocalIndication -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.Text -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import com.example.livingai_lg.ui.models.AnimalType - - -@Composable -fun AnimalTypeSelector( - animalTypes: List, - selectedAnimalType: MutableState, - onAnimalTypeSelected: (String) -> Unit -) { - val selectedAnimalType: String = selectedAnimalType.value ?: "" - - LazyRow( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 12.dp), - horizontalArrangement = Arrangement.spacedBy(12.dp) - ) { - items(animalTypes.size) { index -> - AnimalTypeButton( - animalType = animalTypes[index], - isSelected = selectedAnimalType == animalTypes[index].id, - onClick = { onAnimalTypeSelected(animalTypes[index].id) } - ) - } - } -} - -@Composable -private fun AnimalTypeButton( - animalType: AnimalType, - isSelected: Boolean, - onClick: () -> Unit -) { - Column( - modifier = Modifier - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() }, - onClick = onClick - ) - .padding(4.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - Box( - modifier = Modifier - .size(48.dp) - .background( - if (isSelected) Color(0xFFEDE9FE) else Color.White, - RoundedCornerShape(24.dp) - ), - contentAlignment = Alignment.Center - ) { - Text( - text = animalType.emoji, - fontSize = 24.sp - ) - } - - Text( - text = animalType.name, - fontSize = 12.sp, - fontWeight = FontWeight.Medium, - color = Color(0xFF0A0A0A), - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } -} +package com.example.livingai_lg.ui.components + +import androidx.compose.foundation.LocalIndication +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.livingai_lg.ui.models.AnimalType + + +@Composable +fun AnimalTypeSelector( + animalTypes: List, + selectedAnimalType: String?, + onAnimalTypeSelected: (String) -> Unit +) { + val selectedAnimalType: String = selectedAnimalType ?: "" + + LazyRow( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 12.dp), + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + items(animalTypes.size) { index -> + AnimalTypeButton( + animalType = animalTypes[index], + isSelected = selectedAnimalType == animalTypes[index].id, + onClick = { onAnimalTypeSelected(animalTypes[index].id) } + ) + } + } +} + +@Composable +private fun AnimalTypeButton( + animalType: AnimalType, + isSelected: Boolean, + onClick: () -> Unit +) { + Column( + modifier = Modifier + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() }, + onClick = onClick + ) + .padding(4.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + Box( + modifier = Modifier + .size(48.dp) + .background( + if (isSelected) Color(0xFFEDE9FE) else Color.White, + RoundedCornerShape(24.dp) + ), + contentAlignment = Alignment.Center + ) { + Text( + text = animalType.emoji, + fontSize = 24.sp + ) + } + + Text( + text = animalType.name, + fontSize = 12.sp, + fontWeight = FontWeight.Medium, + color = Color(0xFF0A0A0A), + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } +} diff --git a/app/src/main/java/com/example/livingai_lg/ui/components/BottomNavigationBar.kt b/app/src/main/java/com/example/livingai_lg/ui/components/BottomNavigationBar.kt index fbb47bf..7b1cda4 100644 --- a/app/src/main/java/com/example/livingai_lg/ui/components/BottomNavigationBar.kt +++ b/app/src/main/java/com/example/livingai_lg/ui/components/BottomNavigationBar.kt @@ -1,93 +1,103 @@ -package com.example.livingai_lg.ui.components - -import androidx.compose.foundation.LocalIndication -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.* -import androidx.compose.material3.Icon -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import com.example.livingai_lg.ui.models.BottomNavItemData - -@Composable -fun BottomNavigationBar( - modifier: Modifier = Modifier, - items: List, - currentItem: String, - onItemClick: (route: String) -> Unit = {} -) { - Column( - modifier = modifier - .fillMaxWidth() - .background(Color.White) - .border(1.dp, Color(0xFF000000).copy(alpha = 0.1f)) - ) { - Row( - modifier = Modifier - .fillMaxWidth() - .height(66.dp) - .padding(horizontal = 8.dp), - horizontalArrangement = Arrangement.SpaceEvenly, - verticalAlignment = Alignment.CenterVertically - ) { - - items.forEach { item -> - val isSelected = item.label == currentItem - BottomNavItem( - label = item.label, - iconRes = item.iconRes, - selected = isSelected, - onClick = { - if (!isSelected) { - onItemClick(item.route) - } - } - ) - } - } - } -} - -@Composable -fun BottomNavItem( - label: String, - iconRes: Int, - selected: Boolean, - onClick: () -> Unit = {} -) { - val color = if (selected) Color(0xFF1E88E5) else Color(0xFF0A0A0A) - - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(4.dp), - modifier = Modifier - .padding(vertical = 4.dp) - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() }, - onClick = onClick) - ) { - Icon( - painter = painterResource(iconRes), - contentDescription = label, - tint = color, - modifier = Modifier.size(24.dp) - ) - Text( - text = label, - fontSize = 12.sp, - fontWeight = FontWeight.Medium, - color = color - ) - } -} +package com.example.livingai_lg.ui.components + +import androidx.compose.foundation.LocalIndication +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.livingai_lg.ui.models.BottomNavItemData + +@Composable +fun BottomNavigationBar( + modifier: Modifier = Modifier, + items: List, + currentItem: String, + onItemClick: (route: String) -> Unit = {} +) { + Column( + modifier = modifier + .fillMaxWidth() + .background(Color.White) + .border(1.dp, Color(0xFF000000).copy(alpha = 0.1f)) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .height(66.dp) + .padding(horizontal = 8.dp), + horizontalArrangement = Arrangement.SpaceEvenly, + verticalAlignment = Alignment.CenterVertically + ) { + + items.forEach { item -> + val isSelected = item.label == currentItem + BottomNavItem( + label = item.label, + iconRes = item.iconRes, + selected = isSelected, + onClick = { + if (!isSelected) { + onItemClick(item.route) + } + } + ) + } + } + } +} + +@Composable +fun BottomNavItem( + label: String, + iconRes: Any, + selected: Boolean, + onClick: () -> Unit = {} +) { + val color = if (selected) Color(0xFF1E88E5) else Color(0xFF0A0A0A) + + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(4.dp), + modifier = Modifier + .padding(vertical = 4.dp) + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() }, + onClick = onClick) + ) { + if(iconRes is Int) { + Icon( + painter = painterResource(iconRes), + contentDescription = label, + tint = color, + modifier = Modifier.size(24.dp) + ) + } else if(iconRes is ImageVector) { + Icon( + imageVector = iconRes, + contentDescription = label, + tint = color, + modifier = Modifier.size(24.dp) + ) + } + Text( + text = label, + fontSize = 12.sp, + fontWeight = FontWeight.Medium, + color = color + ) + } +} diff --git a/app/src/main/java/com/example/livingai_lg/ui/components/DropdownInput.kt b/app/src/main/java/com/example/livingai_lg/ui/components/DropdownInput.kt index 8b98f62..62b2051 100644 --- a/app/src/main/java/com/example/livingai_lg/ui/components/DropdownInput.kt +++ b/app/src/main/java/com/example/livingai_lg/ui/components/DropdownInput.kt @@ -1,117 +1,118 @@ -package com.example.livingai_lg.ui.components - -import androidx.compose.foundation.LocalIndication -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowDropDown -import androidx.compose.material3.* -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.shadow -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import com.example.livingai_lg.ui.theme.AppTypography -import com.example.livingai_lg.ui.theme.FarmTextDark - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun DropdownInput( - label: String? = null, // optional label - selected: String, - options: List, - expanded: Boolean, - onExpandedChange: (Boolean) -> Unit, - onSelect: (String) -> Unit, - placeholder: String = "Select", // NEW - custom placeholder - modifier: Modifier = Modifier // NEW - allows width control -) { - Column( - modifier = modifier, // <-- now caller can control width - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - // Optional label - if (label != null) { - Text( - text = label, - fontSize = AppTypography.Body, - fontWeight = FontWeight.Medium, - color = FarmTextDark - ) - } else { - // Reserve label space so layout doesn’t shift - Spacer(modifier = Modifier.height(20.dp)) // ← same height as label text line - } - - ExposedDropdownMenuBox( - expanded = expanded, - onExpandedChange = { onExpandedChange(!expanded) } - ) { - // Anchor box - Box( - modifier = Modifier - .menuAnchor() - .fillMaxWidth() - .height(52.dp) - .shadow(2.dp, RoundedCornerShape(16.dp)) - .background(Color.White, RoundedCornerShape(16.dp)) - .border(1.dp, Color(0xFFE5E7EB), RoundedCornerShape(16.dp)) - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() } - ) { - onExpandedChange(true) - } - .padding(horizontal = 16.dp), - contentAlignment = Alignment.CenterStart - ) { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - - // Custom placeholder support - Text( - text = selected.ifEmpty { placeholder }, - fontSize = AppTypography.Body, - color = if (selected.isEmpty()) Color(0xFF99A1AF) else FarmTextDark - ) - - Icon( - imageVector = Icons.Default.ArrowDropDown, - contentDescription = "Dropdown", - tint = FarmTextDark - ) - - } - } - - // Material3 Dropdown - ExposedDropdownMenu( - expanded = expanded, - onDismissRequest = { onExpandedChange(false) }, - modifier = Modifier.background(Color.White) - ) { - options.forEach { item -> - DropdownMenuItem( - text = { - Text(item, fontSize = AppTypography.Body, color = FarmTextDark) - }, - onClick = { - onSelect(item) - onExpandedChange(false) - } - ) - } - } - } - } -} +package com.example.livingai_lg.ui.components + +import androidx.compose.foundation.LocalIndication +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.livingai_lg.ui.theme.AppTypography +import com.example.livingai_lg.ui.theme.FarmTextDark + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DropdownInput( + label: String? = null, // optional label + selected: String, + options: List, + expanded: Boolean, + onExpandedChange: (Boolean) -> Unit, + onSelect: (String) -> Unit, + placeholder: String = "Select", // NEW - custom placeholder + textColor: Color = Color.Black, + modifier: Modifier = Modifier // NEW - allows width control +) { + Column( + modifier = modifier, // <-- now caller can control width + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + // Optional label +// if (label != null) { + Text( + text = label?:" ", + fontSize = AppTypography.Body, + fontWeight = FontWeight.Medium, + color = FarmTextDark + ) +// } else { +// // Reserve label space so layout doesn’t shift +// Spacer(modifier = Modifier.height(20.dp)) // ← same height as label text line +// } + + ExposedDropdownMenuBox( + expanded = expanded, + onExpandedChange = { onExpandedChange(!expanded) } + ) { + // Anchor box + Box( + modifier = Modifier + .menuAnchor() + .fillMaxWidth() + .height(52.dp) + .shadow(2.dp, RoundedCornerShape(16.dp)) + .background(Color.White, RoundedCornerShape(16.dp)) + .border(1.dp, Color(0xFFE5E7EB), RoundedCornerShape(16.dp)) + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() } + ) { + onExpandedChange(true) + } + .padding(horizontal = 16.dp), + contentAlignment = Alignment.CenterStart + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + + // Custom placeholder support + Text( + text = selected.ifEmpty { placeholder }, + fontSize = AppTypography.Body, + color = if (selected.isEmpty()) Color(0xFF99A1AF) else textColor + ) + + Icon( + imageVector = Icons.Default.ArrowDropDown, + contentDescription = "Dropdown", + tint = FarmTextDark + ) + + } + } + + // Material3 Dropdown + ExposedDropdownMenu( + expanded = expanded, + onDismissRequest = { onExpandedChange(false) }, + modifier = Modifier.background(Color.White) + ) { + options.forEach { item -> + DropdownMenuItem( + text = { + Text(item, fontSize = AppTypography.Body, color = FarmTextDark) + }, + onClick = { + onSelect(item) + onExpandedChange(false) + } + ) + } + } + } + } +} diff --git a/app/src/main/java/com/example/livingai_lg/ui/components/FilterOverlay.kt b/app/src/main/java/com/example/livingai_lg/ui/components/FilterOverlay.kt index d1b2313..7166431 100644 --- a/app/src/main/java/com/example/livingai_lg/ui/components/FilterOverlay.kt +++ b/app/src/main/java/com/example/livingai_lg/ui/components/FilterOverlay.kt @@ -1,74 +1,77 @@ -package com.example.livingai_lg.ui.components - -import androidx.activity.compose.BackHandler -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.slideInHorizontally -import androidx.compose.animation.slideInVertically -import androidx.compose.animation.slideOutHorizontally -import androidx.compose.animation.slideOutVertically -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.* -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.dp -import com.example.livingai_lg.ui.screens.FilterScreen - -@Composable -fun FilterOverlay( - visible: Boolean, - onDismiss: () -> Unit, - onSubmitClick: () -> Unit = {}, -) { - BackHandler(enabled = visible) { onDismiss() } - - Box( - modifier = Modifier.fillMaxSize() - ) { - // Dimmed background - AnimatedVisibility( - visible = visible, - enter = fadeIn(), - exit = fadeOut() - ) { - Box( - modifier = Modifier - .fillMaxSize() - .background(Color.Black.copy(alpha = 0.35f)) - .clickable( - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) { onDismiss() } - ) - } - - // Sliding panel - AnimatedVisibility( - visible = visible, - enter = slideInHorizontally( - initialOffsetX = { it } // from right - ), - exit = slideOutHorizontally( - targetOffsetX = { it } // to right - ), - modifier = Modifier - .fillMaxHeight() - .align(Alignment.CenterEnd) - ) { - FilterScreen( - onBackClick = onDismiss, - onCancelClick = onDismiss, - onSubmitClick = { - onSubmitClick() - onDismiss() - } - ) - } - } -} +package com.example.livingai_lg.ui.components + +import androidx.activity.compose.BackHandler +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.slideInHorizontally +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutHorizontally +import androidx.compose.animation.slideOutVertically +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import com.example.livingai_lg.ui.models.FiltersState +import com.example.livingai_lg.ui.screens.FilterScreen + +@Composable +fun FilterOverlay( + visible: Boolean, + appliedFilters: FiltersState, + onDismiss: () -> Unit, + onSubmitClick: (filters: FiltersState) -> Unit = {}, +) { + BackHandler(enabled = visible) { onDismiss() } + + Box( + modifier = Modifier.fillMaxSize() + ) { + // Dimmed background + AnimatedVisibility( + visible = visible, + enter = fadeIn(), + exit = fadeOut() + ) { + Box( + modifier = Modifier + .fillMaxSize() + .background(Color.Black.copy(alpha = 0.35f)) + .clickable( + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { onDismiss() } + ) + } + + // Sliding panel + AnimatedVisibility( + visible = visible, + enter = slideInHorizontally( + initialOffsetX = { it } // from right + ), + exit = slideOutHorizontally( + targetOffsetX = { it } // to right + ), + modifier = Modifier + .fillMaxHeight() + .align(Alignment.CenterEnd) + ) { + FilterScreen( + appliedFilters, + onBackClick = onDismiss, + onCancelClick = onDismiss, + onSubmitClick = { filters -> + onSubmitClick(filters) + onDismiss() + } + ) + } + } +} diff --git a/app/src/main/java/com/example/livingai_lg/ui/components/RangeFilter.kt b/app/src/main/java/com/example/livingai_lg/ui/components/RangeFilter.kt index a38cb52..5f3dbd1 100644 --- a/app/src/main/java/com/example/livingai_lg/ui/components/RangeFilter.kt +++ b/app/src/main/java/com/example/livingai_lg/ui/components/RangeFilter.kt @@ -1,137 +1,142 @@ -package com.example.livingai_lg.ui.components - -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.BasicTextField -import androidx.compose.material3.* -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import kotlin.math.roundToInt - -@Composable -fun RangeFilter( - modifier: Modifier = Modifier, - - label: String, - min: Int, - max: Int, - valueFrom: Int, - valueTo: Int, - onValueChange: (from: Int, to: Int) -> Unit, - showSlider: Boolean = true, - valueFormatter: (Int) -> String = { it.toString() } -) { - var fromValue by remember(valueFrom) { mutableStateOf(valueFrom) } - var toValue by remember(valueTo) { mutableStateOf(valueTo) } - - Column(modifier = modifier, - verticalArrangement = Arrangement.spacedBy(12.dp)) { - - // Label - Text( - text = label, - fontSize = 16.sp, - fontWeight = FontWeight.SemiBold, - color = Color(0xFF364153) - ) - - // Slider (optional) - if (showSlider) { - RangeSlider( - value = fromValue.toFloat()..toValue.toFloat(), - onValueChange = { range -> - fromValue = range.start.roundToInt() - .coerceIn(min, toValue) - toValue = range.endInclusive.roundToInt() - .coerceIn(fromValue, max) - - onValueChange(fromValue, toValue) - }, - valueRange = min.toFloat()..max.toFloat(), - colors = SliderDefaults.colors( - thumbColor = Color(0xFFD9D9D9), - activeTrackColor = Color(0xFFD9D9D9), - inactiveTrackColor = Color(0xFFE5E7EB) - ) - ) - } - - // Pills - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(8.dp), - verticalAlignment = Alignment.CenterVertically - ) { - RangePill( - modifier = Modifier.weight(1f), - value = fromValue, - onValueChange = { newFrom -> - val safeFrom = newFrom.coerceIn(min, toValue) - fromValue = safeFrom - onValueChange(safeFrom, toValue) - }, - formatter = valueFormatter - ) - - Text("to", fontSize = 15.sp) - - RangePill( - modifier = Modifier.weight(1f), - value = toValue, - onValueChange = { newTo -> - val safeTo = newTo.coerceIn(fromValue, max) - toValue = safeTo - onValueChange(fromValue, safeTo) - }, - formatter = valueFormatter - ) - } - - } -} - -@Composable -private fun RangePill( - modifier: Modifier = Modifier, - value: Int, - onValueChange: (Int) -> Unit, - formatter: (Int) -> String -) { - var text by remember(value) { - mutableStateOf(formatter(value)) - } - - Box( - modifier = modifier - .height(30.dp) - .background(Color.White, RoundedCornerShape(16.dp)) - .border(1.dp, Color(0x12000000), RoundedCornerShape(16.dp)) - .padding(horizontal = 8.dp), - contentAlignment = Alignment.Center - ) { - BasicTextField( - value = text, - onValueChange = { input -> - val digits = input.filter { it.isDigit() } - text = digits - digits.toIntOrNull()?.let(onValueChange) - }, - singleLine = true, - textStyle = TextStyle( - fontSize = 14.sp, - color = Color(0xFF99A1AF) - ), - keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) - ) - } -} +package com.example.livingai_lg.ui.components + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import kotlin.math.roundToInt + +@Composable +fun RangeFilter( + modifier: Modifier = Modifier, + + label: String, + min: Int, + max: Int, + valueFrom: Int, + valueTo: Int, + modified: Boolean = false, + onValueChange: (from: Int, to: Int) -> Unit, + showSlider: Boolean = true, + valueFormatter: (Int) -> String = { it.toString() } +) { + var fromValue by remember(valueFrom) { mutableStateOf(valueFrom) } + var toValue by remember(valueTo) { mutableStateOf(valueTo) } + + Column(modifier = modifier, + verticalArrangement = Arrangement.spacedBy(12.dp)) { + + // Label + Text( + text = label, + fontSize = 16.sp, + fontWeight = FontWeight.SemiBold, + color = Color(0xFF364153) + ) + + // Slider (optional) + if (showSlider) { + RangeSlider( + value = fromValue.toFloat()..toValue.toFloat(), + onValueChange = { range -> + fromValue = range.start.roundToInt() + .coerceIn(min, toValue) + toValue = range.endInclusive.roundToInt() + .coerceIn(fromValue, max) + + onValueChange(fromValue, toValue) + }, + valueRange = min.toFloat()..max.toFloat(), + colors = SliderDefaults.colors( + thumbColor = Color(0xFFD9D9D9), + activeTrackColor = Color(0xFFD9D9D9), + inactiveTrackColor = Color(0xFFE5E7EB) + ) + ) + } + + // Pills + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + RangePill( + modifier = Modifier.weight(1f), + value = fromValue, + modified = modified, + onValueChange = { newFrom -> + val safeFrom = newFrom.coerceIn(min, toValue) + fromValue = safeFrom + onValueChange(safeFrom, toValue) + }, + formatter = valueFormatter + ) + + Text("to", fontSize = 15.sp) + + RangePill( + modifier = Modifier.weight(1f), + value = toValue, + modified = modified, + onValueChange = { newTo -> + val safeTo = newTo.coerceIn(fromValue, max) + toValue = safeTo + onValueChange(fromValue, safeTo) + }, + formatter = valueFormatter + ) + } + + } +} + +@Composable +private fun RangePill( + modifier: Modifier = Modifier, + value: Int, + modified: Boolean = false, + onValueChange: (Int) -> Unit, + formatter: (Int) -> String +) { + var text by remember(value) { + mutableStateOf(formatter(value)) + } + + Box( + modifier = modifier + .height(30.dp) + .background(Color.White, RoundedCornerShape(16.dp)) + .border(1.dp, Color(0x12000000), RoundedCornerShape(16.dp)) + .padding(horizontal = 8.dp), + contentAlignment = Alignment.Center + ) { + var modified = modified; + BasicTextField( + value = text, + onValueChange = { input -> + val digits = input.filter { it.isDigit() } + text = digits + digits.toIntOrNull()?.let(onValueChange) + }, + singleLine = true, + textStyle = TextStyle( + fontSize = 14.sp, + color = if(modified) Color.Black else Color(0xFF99A1AF) + ), + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number) + ) + } +} diff --git a/app/src/main/java/com/example/livingai_lg/ui/components/wishlistNameOverlay.kt b/app/src/main/java/com/example/livingai_lg/ui/components/wishlistNameOverlay.kt new file mode 100644 index 0000000..c14edc4 --- /dev/null +++ b/app/src/main/java/com/example/livingai_lg/ui/components/wishlistNameOverlay.kt @@ -0,0 +1,80 @@ +package com.example.livingai_lg.ui.components + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun WishlistNameOverlay( + onSave: (String) -> Unit, + onDismiss: () -> Unit +) { + var name by remember { mutableStateOf("") } + + AnimatedVisibility( + visible = true, + enter = slideInVertically { -it }, + exit = slideOutVertically { -it } + ) { + Box( + Modifier + .fillMaxWidth() + .background(Color.White) + .padding(16.dp) + ) { + Column(verticalArrangement = Arrangement.spacedBy(12.dp)) { + Text( + text = "Save Filters", + fontSize = 18.sp, + fontWeight = FontWeight.SemiBold + ) + + OutlinedTextField( + value = name, + onValueChange = { name = it }, + placeholder = { Text("Wishlist name") }, + singleLine = true + ) + + Row( + horizontalArrangement = Arrangement.End, + modifier = Modifier.fillMaxWidth() + ) { + TextButton(onClick = onDismiss) { + Text("Cancel") + } + Button( + onClick = { + if (name.isNotBlank()) { + onSave(name) + } + } + ) { + Text("Save") + } + } + } + } + } +} diff --git a/app/src/main/java/com/example/livingai_lg/ui/models/BottomNavItemData.kt b/app/src/main/java/com/example/livingai_lg/ui/models/BottomNavItemData.kt index e3a838b..20ec3a7 100644 --- a/app/src/main/java/com/example/livingai_lg/ui/models/BottomNavItemData.kt +++ b/app/src/main/java/com/example/livingai_lg/ui/models/BottomNavItemData.kt @@ -1,25 +1,28 @@ -package com.example.livingai_lg.ui.models - -import com.example.livingai_lg.R -import com.example.livingai_lg.ui.navigation.AppScreen - -data class BottomNavItemData( - val label: String, - val iconRes: Int, - val route: String, -) - -val mainBottomNavItems = listOf( - BottomNavItemData("Home", R.drawable.ic_home , AppScreen.BUY_ANIMALS), - BottomNavItemData("Sell", R.drawable.ic_tag, AppScreen.CREATE_ANIMAL_LISTING), - // TODO: - BottomNavItemData("Chats", R.drawable.ic_chat, AppScreen.CHATS), - BottomNavItemData("Services", R.drawable.ic_config, AppScreen.CREATE_PROFILE), - BottomNavItemData("Mandi", R.drawable.ic_market, AppScreen.CREATE_PROFILE) -) - -val chatBottomNavItems = listOf( - BottomNavItemData("Contacts", R.drawable.ic_home ,"home"), - BottomNavItemData("Calls", R.drawable.ic_tag, "sell"), - BottomNavItemData("Chats", R.drawable.ic_chat, "chats"), - ) +package com.example.livingai_lg.ui.models + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Build +import androidx.compose.material.icons.outlined.Home +import com.example.livingai_lg.R +import com.example.livingai_lg.ui.navigation.AppScreen + +data class BottomNavItemData( + val label: String, + val iconRes: Any, + val route: String, +) + +val mainBottomNavItems = listOf( + BottomNavItemData("Home", R.drawable.ic_home , AppScreen.BUY_ANIMALS), + BottomNavItemData("Sell", R.drawable.ic_tag, AppScreen.CREATE_ANIMAL_LISTING), + // TODO: + BottomNavItemData("Chats", R.drawable.ic_chat, AppScreen.CHATS), + BottomNavItemData("Services", R.drawable.ic_config, AppScreen.CREATE_PROFILE), + BottomNavItemData("Mandi", R.drawable.ic_shop2, AppScreen.CREATE_PROFILE) +) + +val chatBottomNavItems = listOf( + BottomNavItemData("Contacts", R.drawable.ic_home ,AppScreen.CONTACTS), + BottomNavItemData("Calls", R.drawable.ic_tag, AppScreen.CALLS), + BottomNavItemData("Chats", R.drawable.ic_chat, AppScreen.CHATS), + ) diff --git a/app/src/main/java/com/example/livingai_lg/ui/models/FilterState.kt b/app/src/main/java/com/example/livingai_lg/ui/models/FilterState.kt new file mode 100644 index 0000000..9013331 --- /dev/null +++ b/app/src/main/java/com/example/livingai_lg/ui/models/FilterState.kt @@ -0,0 +1,42 @@ +package com.example.livingai_lg.ui.models + +data class TextFilter( + val value: String = "", + val filterSet: Boolean = false +) + +data class RangeFilterState( + val min: Int, + val max: Int, + val filterSet: Boolean = false +) + +data class FiltersState( + val animal: TextFilter = TextFilter(), + val breed: TextFilter = TextFilter(), + val distance: TextFilter = TextFilter(), + val gender: TextFilter = TextFilter(), + + val price: RangeFilterState = RangeFilterState(0, 90_000), + val age: RangeFilterState = RangeFilterState(0, 20), + val weight: RangeFilterState = RangeFilterState(0, 9_000), + val milkYield: RangeFilterState = RangeFilterState(0, 900), + + val pregnancyStatuses: Set = emptySet(), + + val calving: RangeFilterState = RangeFilterState(0, 10) +) + + +fun FiltersState.isDefault(): Boolean { + return animal.filterSet.not() && + breed.filterSet.not() && + distance.filterSet.not() && + gender.filterSet.not() && + price.filterSet.not() && + age.filterSet.not() && + weight.filterSet.not() && + milkYield.filterSet.not() && + pregnancyStatuses.isEmpty() && + calving.filterSet.not() +} diff --git a/app/src/main/java/com/example/livingai_lg/ui/models/Wishlist.kt b/app/src/main/java/com/example/livingai_lg/ui/models/Wishlist.kt new file mode 100644 index 0000000..c8b48a5 --- /dev/null +++ b/app/src/main/java/com/example/livingai_lg/ui/models/Wishlist.kt @@ -0,0 +1,32 @@ +package com.example.livingai_lg.ui.models + +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import java.util.UUID + +data class WishlistEntry( + val id: String = UUID.randomUUID().toString(), + val name: String, + val filters: FiltersState, + val createdAt: Long = System.currentTimeMillis() +) + +object WishlistStore { + + private val _wishlist = + MutableStateFlow>(emptyList()) + + val wishlist: StateFlow> = _wishlist + + fun add(entry: WishlistEntry) { + _wishlist.value = _wishlist.value + entry + } + + fun remove(id: String) { + _wishlist.value = _wishlist.value.filterNot { it.id == id } + } + + fun clear() { + _wishlist.value = emptyList() + } +} diff --git a/app/src/main/java/com/example/livingai_lg/ui/navigation/AppNavigation.kt b/app/src/main/java/com/example/livingai_lg/ui/navigation/AppNavigation.kt index f39e1c0..c8c9921 100644 --- a/app/src/main/java/com/example/livingai_lg/ui/navigation/AppNavigation.kt +++ b/app/src/main/java/com/example/livingai_lg/ui/navigation/AppNavigation.kt @@ -281,30 +281,30 @@ fun AppNavigation( ) } - composable(AppScreen.BUY_ANIMALS_FILTERS) { - FilterScreen( - onBackClick = { - navController.popBackStack() - }, - onSubmitClick = {navController.navigate(AppScreen.BUY_ANIMALS)}, - onCancelClick = { - navController.popBackStack() - }, - ) - } +// composable(AppScreen.BUY_ANIMALS_FILTERS) { +// FilterScreen( +// onBackClick = { +// navController.popBackStack() +// }, +// onSubmitClick = {navController.navigate(AppScreen.BUY_ANIMALS)}, +// onCancelClick = { +// navController.popBackStack() +// }, +// ) +// } - composable(AppScreen.BUY_ANIMALS_SORT) { - SortScreen( - onApplyClick = {navController.navigate(AppScreen.BUY_ANIMALS)}, - onBackClick = { - navController.popBackStack() - }, - onCancelClick = { - navController.popBackStack() - }, - - ) - } +// composable(AppScreen.BUY_ANIMALS_SORT) { +// SortScreen( +// onApplyClick = {navController.navigate(AppScreen.BUY_ANIMALS)}, +// onBackClick = { +// navController.popBackStack() +// }, +// onCancelClick = { +// navController.popBackStack() +// }, +// +// ) +// } composable(AppScreen.SAVED_LISTINGS) { SavedListingsScreen( diff --git a/app/src/main/java/com/example/livingai_lg/ui/navigation/navigation_legacy/MainNavGraph.kt b/app/src/main/java/com/example/livingai_lg/ui/navigation/navigation_legacy/MainNavGraph.kt index 367bc46..28b3d2c 100644 --- a/app/src/main/java/com/example/livingai_lg/ui/navigation/navigation_legacy/MainNavGraph.kt +++ b/app/src/main/java/com/example/livingai_lg/ui/navigation/navigation_legacy/MainNavGraph.kt @@ -95,17 +95,17 @@ fun NavGraphBuilder.mainNavGraph(navController: NavController) { } - composable(AppScreen.BUY_ANIMALS_FILTERS) { - FilterScreen( - onBackClick = { - navController.popBackStack() - }, - onSubmitClick = {navController.navigate(AppScreen.BUY_ANIMALS)}, - onCancelClick = { - navController.popBackStack() - }, - ) - } +// composable(AppScreen.BUY_ANIMALS_FILTERS) { +// FilterScreen( +// onBackClick = { +// navController.popBackStack() +// }, +// onSubmitClick = {navController.navigate(AppScreen.BUY_ANIMALS)}, +// onCancelClick = { +// navController.popBackStack() +// }, +// ) +// } composable(AppScreen.BUY_ANIMALS_SORT) { SortScreen( diff --git a/app/src/main/java/com/example/livingai_lg/ui/screens/BuyScreen.kt b/app/src/main/java/com/example/livingai_lg/ui/screens/BuyScreen.kt index c256ef0..b281169 100644 --- a/app/src/main/java/com/example/livingai_lg/ui/screens/BuyScreen.kt +++ b/app/src/main/java/com/example/livingai_lg/ui/screens/BuyScreen.kt @@ -138,7 +138,7 @@ fun BuyScreen( // Animal type filter buttons AnimalTypeSelector( animalTypes = animalTypes, - selectedAnimalType = selectedAnimalType + selectedAnimalType = ) { } // Ad space banner diff --git a/app/src/main/java/com/example/livingai_lg/ui/screens/FilterScreen.kt b/app/src/main/java/com/example/livingai_lg/ui/screens/FilterScreen.kt index 8583c34..0132e03 100644 --- a/app/src/main/java/com/example/livingai_lg/ui/screens/FilterScreen.kt +++ b/app/src/main/java/com/example/livingai_lg/ui/screens/FilterScreen.kt @@ -1,467 +1,569 @@ -package com.example.livingai_lg.ui.screens - -import androidx.activity.compose.BackHandler -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.slideInHorizontally -import androidx.compose.animation.slideOutHorizontally -import androidx.compose.foundation.BorderStroke -import androidx.compose.foundation.LocalIndication -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ArrowForwardIos -import androidx.compose.material.icons.filled.ArrowBack -import androidx.compose.material.icons.filled.ArrowForwardIos -import androidx.compose.material.icons.filled.Check -import androidx.compose.material3.* -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextDecoration -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import com.example.livingai_lg.ui.components.DropdownInput -import com.example.livingai_lg.ui.components.RangeFilter -import com.example.livingai_lg.ui.theme.AppTypography - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun FilterScreen( - onBackClick: () -> Unit = {}, - onSubmitClick: () -> Unit = {}, - onCancelClick: () -> Unit = {}, -) { - var selectedAnimal by remember { mutableStateOf("") } - var selectedBreed by remember { mutableStateOf("") } - var selectedDistance by remember { mutableStateOf("") } - var selectedGender by remember { mutableStateOf("") } - - var animalExpanded by remember { mutableStateOf(false) } - var breedExpanded by remember { mutableStateOf(false) } - var distanceExpanded by remember { mutableStateOf(false) } - var genderExpanded by remember { mutableStateOf(false) } - - var priceFrom by remember { mutableStateOf("0") } - var priceTo by remember { mutableStateOf("90,000") } - var priceSliderValue by remember { mutableFloatStateOf(0f) } - - var ageFrom by remember { mutableStateOf("1") } - var ageTo by remember { mutableStateOf("20") } - - var selectedPregnancyStatus by remember { mutableStateOf(setOf()) } - - var weightFrom by remember { mutableStateOf("0") } - var weightTo by remember { mutableStateOf("9000") } - - var milkYieldFrom by remember { mutableStateOf("0") } - var milkYieldTo by remember { mutableStateOf("900") } - - var calvingFrom by remember { mutableStateOf(0) } - var calvingTo by remember { mutableStateOf(10) } - - var calvingFromExpanded by remember { mutableStateOf(false) } - var calvingToExpanded by remember { mutableStateOf(false) } - - val maxCalving = 10 - - val calvingFromOptions = (0..maxCalving).map { it.toString() } - val calvingToOptions = (calvingFrom..maxCalving).map { it.toString() } - - Column( - modifier = Modifier - .fillMaxHeight() - .background(Color(0xFFF7F4EE)) - ) { - // Header - Box( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 16.dp) - ) { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - IconButton(onClick = onBackClick) { - Icon( - imageVector = Icons.AutoMirrored.Filled.ArrowForwardIos, - contentDescription = "Back", - tint = Color(0xFF0A0A0A) - ) - } - - Text( - text = "Filters", - fontSize = 32.sp, - fontWeight = FontWeight.Normal, - color = Color.Black - ) - } - } - } - - // Scrollable Content - Column( - modifier = Modifier - .fillMaxSize() - .verticalScroll(rememberScrollState()) - .padding(horizontal = 32.dp) - .padding(bottom = 24.dp), - verticalArrangement = Arrangement.spacedBy(24.dp) - ) { - // Animal Section - Column( - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - DropdownInput( - label = "Animal", - selected = selectedAnimal, - options = listOf("Cow", "Buffalo", "Goat", "Sheep"), - expanded = animalExpanded, - onExpandedChange = { animalExpanded = it }, - onSelect = { item -> - selectedAnimal = item - animalExpanded = false - }, - placeholder = "Select Animal", // <--- half width - ) - } - - // Breed Section - Column( - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - DropdownInput( - label = "Breed", - selected = selectedBreed, - options = listOf("Holstein", "Jersey", "Gir", "Sahiwal"), - expanded = breedExpanded, - onExpandedChange = { breedExpanded = it }, - onSelect = { item -> - selectedBreed = item - breedExpanded = false - }, - placeholder = "Select Breed", // <--- half width - ) - } - - // Price and Age Row - - Column( - verticalArrangement = Arrangement.spacedBy(8.dp) - - ) { - RangeFilter( - modifier = Modifier.fillMaxWidth(), // 👈 important - label = "Price", - min = 0, - max = 90_000, - valueFrom = priceFrom.toInt(), - valueTo = priceTo.replace(",", "").toInt(), - onValueChange = { from, to -> - priceFrom = from.toString() - priceTo = to.toString() - } - ) - } - - Column( - verticalArrangement = Arrangement.spacedBy(8.dp) - - ) { - RangeFilter( - modifier = Modifier.fillMaxWidth(), - label = "Age", - min = 0, - max = 20, - valueFrom = ageFrom.toInt(), - valueTo = ageTo.replace(",", "").toInt(), - showSlider = false, - onValueChange = { from, to -> - ageFrom = from.toString() - ageTo = to.toString() - } - ) - } - - - // Distance and Gender Row - - // Distance Section - Column( - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - DropdownInput( - label = "Distance", - selected = selectedDistance, - options = listOf("0-5 km", "5-10 km", "10-20 km", "20+ km"), - expanded = distanceExpanded, - onExpandedChange = { distanceExpanded = it }, - onSelect = { item -> - selectedDistance = item - distanceExpanded = false - }, - placeholder = "Choose Distance", // <--- half width - ) - } - - // Gender Section - Column( - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - DropdownInput( - label = "Gender", - selected = selectedGender, - options = listOf("Male", "Female"), - expanded = genderExpanded, - onExpandedChange = { genderExpanded = it }, - onSelect = { item -> - selectedGender = item - genderExpanded = false - }, - placeholder = "Choose Gender", // <--- half width - ) - } - - - - - // Pregnancy Status Section - Column( - verticalArrangement = Arrangement.spacedBy(12.dp) - ) { - Text( - text = "Pregnancy Status", - fontSize = AppTypography.Body, - fontWeight = FontWeight.SemiBold, - color = Color(0xFF364153) - ) - - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(20.dp) - ) { - listOf("Pregnant", "Calved", "Option").forEach { status -> - PregnancyStatusChip( - label = status, - isSelected = selectedPregnancyStatus.contains(status), - onClick = { - selectedPregnancyStatus = if (selectedPregnancyStatus.contains(status)) { - selectedPregnancyStatus - status - } else { - selectedPregnancyStatus + status - } - } - ) - } - } - } - - - Column( - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - RangeFilter( - modifier = Modifier.fillMaxWidth(), // 👈 important - label = "Weight", - min = 0, - max = 9000, - valueFrom = weightFrom.toInt(), - valueTo = weightTo.replace(",", "").toInt(), - onValueChange = { from, to -> - weightFrom = from.toString() - weightTo = to.toString() - } - ) - } - - Column( - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - RangeFilter( - modifier = Modifier.fillMaxWidth(), - label = "Milk Yield", - min = 0, - max = 900, - valueFrom = milkYieldFrom.toInt(), - valueTo = milkYieldTo.replace(",", "").toInt(), - showSlider = true, - onValueChange = { from, to -> - milkYieldFrom = from.toString() - milkYieldTo = to.toString() - } - ) - } - - - // Calving Number Section - Column( - verticalArrangement = Arrangement.spacedBy(12.dp) - ) { - - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(16.dp), - verticalAlignment = Alignment.CenterVertically - ) { - - // FROM - DropdownInput( - label = "Calving Number", - selected = calvingFrom.toString(), - options = calvingFromOptions, - expanded = calvingFromExpanded, - onExpandedChange = { calvingFromExpanded = it }, - onSelect = { value -> - val newFrom = value.toInt() - calvingFrom = newFrom - - // 👇 enforce invariant - if (calvingTo < newFrom) { - calvingTo = newFrom - } - - calvingFromExpanded = false - }, - placeholder = "From", - modifier = Modifier.weight(1f) - ) - - Text( - text = "to", - fontSize = 20.sp, - color = Color.Black - ) - - // TO - DropdownInput( - selected = calvingTo.toString(), - options = calvingToOptions, // 👈 constrained options - expanded = calvingToExpanded, - onExpandedChange = { calvingToExpanded = it }, - onSelect = { value -> - calvingTo = value.toInt() - calvingToExpanded = false - }, - placeholder = "To", - modifier = Modifier.weight(1f) - ) - } - } - - Spacer(modifier = Modifier.height(24.dp)) - - // Action Buttons - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(16.dp) - ) { - // Submit Button - Button( - onClick = onSubmitClick, - modifier = Modifier - .width(173.dp) - .height(50.dp), - shape = RoundedCornerShape(25.dp), - colors = ButtonDefaults.buttonColors( - containerColor = Color.Black, - contentColor = Color.White - ) - ) { - Text( - text = "Submit", - fontSize = AppTypography.Body, - fontWeight = FontWeight.Normal - ) - } - - // Cancel Button - OutlinedButton( - onClick = onCancelClick, - modifier = Modifier - .width(173.dp) - .height(50.dp), - shape = RoundedCornerShape(25.dp), - border = BorderStroke( - 1.dp, - Color(0x1A000000) - ), - colors = ButtonDefaults.outlinedButtonColors( - containerColor = Color.Transparent, - contentColor = Color(0xFF0A0A0A) - ) - ) { - Text( - text = "Cancel", - fontSize = AppTypography.Body, - fontWeight = FontWeight.Normal - ) - } - } - } - } -} - -@Composable -fun PregnancyStatusChip( - label: String, - isSelected: Boolean, - onClick: () -> Unit -) { - Box( - modifier = Modifier - .height(29.dp) - .widthIn(min = 76.dp) - .background( - if (isSelected) Color(0xFF007BFF) else Color.Transparent, - RoundedCornerShape(24.dp) - ) - .border( - 1.dp, - Color(0xFFE5E7EB), - RoundedCornerShape(24.dp) - ) - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() }, - onClick = onClick) - .padding(horizontal = 12.dp), - contentAlignment = Alignment.Center - ) { - Row( - horizontalArrangement = Arrangement.spacedBy(4.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = label, - fontSize = 10.sp, - fontWeight = FontWeight.Normal, - color = if (isSelected) Color(0xFFF4F4F4) else Color.Black, - textDecoration = TextDecoration.Underline - ) - - if (isSelected) { - Icon( - imageVector = Icons.Default.Check, - contentDescription = "Selected", - tint = Color(0xFFE3E3E3), - modifier = Modifier.size(24.dp) - ) - } - } - } -} +package com.example.livingai_lg.ui.screens + +import androidx.activity.compose.BackHandler +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.slideInHorizontally +import androidx.compose.animation.slideOutHorizontally +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.LocalIndication +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowForwardIos +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.ArrowForwardIos +import androidx.compose.material.icons.filled.Check +import androidx.compose.material.icons.filled.FavoriteBorder +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextDecoration +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.livingai_lg.ui.components.DropdownInput +import com.example.livingai_lg.ui.components.RangeFilter +import com.example.livingai_lg.ui.components.WishlistNameOverlay +import com.example.livingai_lg.ui.models.FiltersState +import com.example.livingai_lg.ui.models.RangeFilterState +import com.example.livingai_lg.ui.models.TextFilter +import com.example.livingai_lg.ui.models.WishlistEntry +import com.example.livingai_lg.ui.models.WishlistStore +import com.example.livingai_lg.ui.models.isDefault +import com.example.livingai_lg.ui.theme.AppTypography + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun FilterScreen( + appliedFilters: FiltersState, + wishlistEditMode: Boolean = false, + onSubmitClick: (FiltersState) -> Unit, + onBackClick: () -> Unit = {}, + onCancelClick: () -> Unit = {}, +) { + var filters by remember { + mutableStateOf(appliedFilters) + } + var showWishlistOverlay by remember { mutableStateOf(false) } + + var selectedAnimal =filters.animal + var selectedBreed = filters.breed + var selectedDistance = filters.distance + var selectedGender = filters.gender + + var animalExpanded by remember { mutableStateOf(false) } + var breedExpanded by remember { mutableStateOf(false) } + var distanceExpanded by remember { mutableStateOf(false) } + var genderExpanded by remember { mutableStateOf(false) } + + var price =filters.price + var age = filters.age + var weight = filters.weight + var milkYield = filters.milkYield + var calving = filters.calving + + var selectedPregnancyStatus = filters.pregnancyStatuses + + + var calvingFromExpanded by remember { mutableStateOf(false) } + var calvingToExpanded by remember { mutableStateOf(false) } + + val maxCalving = 10 + + val calvingFromOptions = (0..maxCalving).map { it.toString() } + val calvingToOptions = (calving.min..maxCalving).map { it.toString() } + + Column( + modifier = Modifier + .fillMaxHeight() + .background(Color(0xFFF7F4EE)) + ) { + // Header + Box( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 16.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + IconButton(onClick = onBackClick) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowForwardIos, + contentDescription = "Back", + tint = Color(0xFF0A0A0A) + ) + } + + Text( + text = "Filters", + fontSize = 32.sp, + fontWeight = FontWeight.Normal, + color = Color.Black + ) + + if(!wishlistEditMode){ + IconButton( + onClick = { + if (!filters.isDefault()) { + showWishlistOverlay = true + } + } + ) { + Icon( + imageVector = Icons.Default.FavoriteBorder, + contentDescription = "Add to Wishlist" + ) + } + } + } + } + } + + // Scrollable Content + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(horizontal = 32.dp) + .padding(bottom = 24.dp), + verticalArrangement = Arrangement.spacedBy(24.dp) + ) { + // Animal Section + Column( + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + DropdownInput( + label = "Animal", + selected = if (selectedAnimal.filterSet) selectedAnimal.value else "", + options = listOf("Cow", "Buffalo", "Goat", "Sheep"), + expanded = animalExpanded, + onExpandedChange = { animalExpanded = it }, + onSelect = { item -> + filters = filters.copy( + animal = TextFilter( + value = item, + filterSet = true + ) + ) + animalExpanded = false + }, + placeholder = "Select Animal", // <--- half width + textColor = if (selectedAnimal.filterSet) Color.Black else Color.Gray + ) + } + + // Breed Section + Column( + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + DropdownInput( + label = "Breed", + selected = if (selectedBreed.filterSet) selectedBreed.value else "", + options = listOf("Holstein", "Jersey", "Gir", "Sahiwal"), + expanded = breedExpanded, + onExpandedChange = { breedExpanded = it }, + onSelect = { item -> + filters = filters.copy( + breed = TextFilter( + value = item, + filterSet = true + ) + ) + breedExpanded = false + }, + placeholder = "Select Breed", // <--- half width + textColor = if (selectedAnimal.filterSet) Color.Black else Color.Gray + ) + } + + // Price and Age Row + + Column( + verticalArrangement = Arrangement.spacedBy(8.dp) + + ) { + RangeFilter( + modifier = Modifier.fillMaxWidth(), // 👈 important + + label = "Price", + min = 0, + max = 90_000, + valueFrom = price.min, + valueTo = price.max, + modified = price.filterSet, + onValueChange = { from, to -> + filters = filters.copy( + price = RangeFilterState( + min = from, + max = to, + filterSet = true + ) + ) + } + ) + } + + Column( + verticalArrangement = Arrangement.spacedBy(8.dp) + + ) { + RangeFilter( + modifier = Modifier.fillMaxWidth(), // 👈 important + + label = "Age (years)", + min = 0, + max = 20, + valueFrom = age.min, + valueTo = age.max, + showSlider = false, + modified = age.filterSet, + onValueChange = { from, to -> + filters = filters.copy( + age = RangeFilterState( + min = from, + max = to, + filterSet = true + ) + ) + } + ) + + } + + + // Distance and Gender Row + + // Distance Section + Column( + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + DropdownInput( + label = "Distance", + selected = if (selectedDistance.filterSet) selectedDistance.value else "", + options = listOf("0-5 km", "5-10 km", "10-20 km", "20+ km"), + expanded = distanceExpanded, + onExpandedChange = { distanceExpanded = it }, + onSelect = { item -> + filters = filters.copy( + distance = TextFilter( + value = item, + filterSet = true + ) + ) + distanceExpanded = false + }, + placeholder = "Choose Distance", // <--- half width + textColor = if (selectedAnimal.filterSet) Color.Black else Color.Gray + ) + } + + // Gender Section + Column( + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + DropdownInput( + label = "Gender", + selected = if (selectedGender.filterSet) selectedGender.value else "", + options = listOf("Male", "Female"), + expanded = genderExpanded, + onExpandedChange = { genderExpanded = it }, + onSelect = { item -> + filters = filters.copy( + gender = TextFilter( + value = item, + filterSet = true + ) + ) + genderExpanded = false + }, + placeholder = "Choose Gender", // <--- half width + textColor = if (selectedAnimal.filterSet) Color.Black else Color.Gray + ) + } + + + + + // Pregnancy Status Section + Column( + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + Text( + text = "Pregnancy Status", + fontSize = AppTypography.Body, + fontWeight = FontWeight.SemiBold, + color = Color(0xFF364153) + ) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(20.dp) + ) { + listOf("Pregnant", "Calved", "Option").forEach { status -> + PregnancyStatusChip( + label = status, + isSelected = selectedPregnancyStatus.contains(status), + onClick = { + filters = filters.copy( + pregnancyStatuses = + if (filters.pregnancyStatuses.contains(status)) + filters.pregnancyStatuses - status + else + filters.pregnancyStatuses + status + ) + } + ) + } + } + } + + + Column( + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + RangeFilter( + modifier = Modifier.fillMaxWidth(), // 👈 important + + label = "Weight", + min = 0, + max = 9000, + valueFrom = weight.min, + valueTo = weight.max, + modified = weight.filterSet, + onValueChange = { from, to -> + filters = filters.copy( + weight = RangeFilterState( + min = from, + max = to, + filterSet = true + ) + ) + } + ) + } + + Column( + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + RangeFilter( + modifier = Modifier.fillMaxWidth(), // 👈 important + + label = "Milk Yield", + min = 0, + max = 900, + valueFrom = milkYield.min, + valueTo = milkYield.max, + modified = milkYield.filterSet, + onValueChange = { from, to -> + filters = filters.copy( + milkYield = RangeFilterState( + min = from, + max = to, + filterSet = true + ) + ) + } + ) + } + + + // Calving Number Section + Column( + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + + // FROM + DropdownInput( + label = "Calving Number", + selected = calving.min.toString(), + options = calvingFromOptions, + expanded = calvingFromExpanded, + onExpandedChange = { calvingFromExpanded = it }, + onSelect = { value -> + val newFrom = value.toInt() + val newTo = maxOf(calving.max, newFrom) + + filters = filters.copy( + calving = RangeFilterState( + min = newFrom, + max = newTo, + filterSet = true + ) + ) + + calvingFromExpanded = false + }, + placeholder = "From", + modifier = Modifier.weight(1f) + ) + + Text( + text = "to", + fontSize = 20.sp, + color = Color.Black + ) + + // TO + DropdownInput( + selected = calving.max.toString(), + options = calvingToOptions, // 👈 constrained options + expanded = calvingToExpanded, + onExpandedChange = { calvingToExpanded = it }, + onSelect = { value -> + val newTo = value.toInt() + val newFrom = minOf(calving.min, newTo) + + filters = filters.copy( + calving = RangeFilterState( + min = newFrom, + max = newTo, + filterSet = true + ) + ) + calvingToExpanded = false + }, + placeholder = "To", + modifier = Modifier.weight(1f) + ) + } + } + + Spacer(modifier = Modifier.height(24.dp)) + + // Action Buttons + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp) + ) { + // Submit Button + Button( + onClick = { onSubmitClick(filters) }, + modifier = Modifier + .width(173.dp) + .height(50.dp), + shape = RoundedCornerShape(25.dp), + colors = ButtonDefaults.buttonColors( + containerColor = Color.Black, + contentColor = Color.White + ) + ) { + Text( + text = "Submit", + fontSize = AppTypography.Body, + fontWeight = FontWeight.Normal + ) + } + + // Cancel Button + OutlinedButton( + onClick = onCancelClick, + modifier = Modifier + .width(173.dp) + .height(50.dp), + shape = RoundedCornerShape(25.dp), + border = BorderStroke( + 1.dp, + Color(0x1A000000) + ), + colors = ButtonDefaults.outlinedButtonColors( + containerColor = Color.Transparent, + contentColor = Color(0xFF0A0A0A) + ) + ) { + Text( + text = "Cancel", + fontSize = AppTypography.Body, + fontWeight = FontWeight.Normal + ) + } + } + } + } + if (showWishlistOverlay) { + WishlistNameOverlay( + onDismiss = { showWishlistOverlay = false }, + onSave = { name -> + WishlistStore.add( + WishlistEntry( + name = name, + filters = filters + ) + ) + showWishlistOverlay = false + } + ) + } +} + +@Composable +fun PregnancyStatusChip( + label: String, + isSelected: Boolean, + onClick: () -> Unit +) { + Box( + modifier = Modifier + .height(29.dp) + .widthIn(min = 76.dp) + .background( + if (isSelected) Color(0xFF007BFF) else Color.Transparent, + RoundedCornerShape(24.dp) + ) + .border( + 1.dp, + Color(0xFFE5E7EB), + RoundedCornerShape(24.dp) + ) + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() }, + onClick = onClick + ) + .padding(horizontal = 12.dp), + contentAlignment = Alignment.Center + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(4.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = label, + fontSize = 10.sp, + fontWeight = FontWeight.Normal, + color = if (isSelected) Color(0xFFF4F4F4) else Color.Black, + textDecoration = TextDecoration.Underline + ) + + if (isSelected) { + Icon( + imageVector = Icons.Default.Check, + contentDescription = "Selected", + tint = Color(0xFFE3E3E3), + modifier = Modifier.size(24.dp) + ) + } + } + } +} diff --git a/app/src/main/java/com/example/livingai_lg/ui/screens/chat/CallsScreen.kt b/app/src/main/java/com/example/livingai_lg/ui/screens/chat/CallsScreen.kt index a2465e0..3ca6f69 100644 --- a/app/src/main/java/com/example/livingai_lg/ui/screens/chat/CallsScreen.kt +++ b/app/src/main/java/com/example/livingai_lg/ui/screens/chat/CallsScreen.kt @@ -1,327 +1,336 @@ -package com.example.farmmarketplace.ui.screens - -import androidx.compose.foundation.LocalIndication -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.automirrored.filled.CallMade -import androidx.compose.material.icons.automirrored.filled.CallMissed -import androidx.compose.material.icons.automirrored.filled.CallReceived -import androidx.compose.material.icons.filled.* -import androidx.compose.material3.Icon -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp - -data class CallRecord( - val id: String, - val name: String, - val initials: String, - val callType: CallType, - val duration: String, - val timestamp: String, - val isVideoCall: Boolean = false -) - -enum class CallType { - INCOMING, - OUTGOING, - MISSED -} - -@Composable -fun CallsScreen( - onBackClick: () -> Unit = {}, - onCallClick: () -> Unit = {}, - onMenuClick: () -> Unit = {}, - onCallItemClick: (String) -> Unit = {}, - onTabClick: (route: String) -> Unit = {} -) { - val callHistory = listOf( - CallRecord( - id = "1", - name = "Farmer Kumar", - initials = "FK", - callType = CallType.INCOMING, - duration = "5m 23s", - timestamp = "Today, 2:30 PM" - ), - CallRecord( - id = "2", - name = "Seller Raj", - initials = "SR", - callType = CallType.OUTGOING, - duration = "2m 10s", - timestamp = "Today, 11:45 AM" - ), - CallRecord( - id = "3", - name = "Buyer Priya", - initials = "BP", - callType = CallType.MISSED, - duration = "", - timestamp = "Yesterday, 8:15 PM" - ), - CallRecord( - id = "4", - name = "Seller 1", - initials = "S1", - callType = CallType.OUTGOING, - duration = "8m 45s", - timestamp = "Yesterday, 5:30 PM", - isVideoCall = true - ), - CallRecord( - id = "5", - name = "Veterinarian", - initials = "V", - callType = CallType.INCOMING, - duration = "12m 30s", - timestamp = "2 days ago" - ) - ) - - Box( - modifier = Modifier - .fillMaxSize() - .background(Color(0xFFFCFBF8)) - ) { - Column( - modifier = Modifier.fillMaxSize() - ) { - CallsHeader( - onBackClick = onBackClick, - onCallClick = onCallClick, - onMenuClick = onMenuClick - ) - - LazyColumn( - modifier = Modifier - .fillMaxWidth() - .weight(1f) - .padding(horizontal = 16.dp, vertical = 16.dp), - verticalArrangement = Arrangement.spacedBy(12.dp) - ) { - items(callHistory) { call -> - CallHistoryItem( - call = call, - onClick = { onCallItemClick(call.id) } - ) - } - } - - ContactsBottomNav( - currentTab = ContactsTab.CALLS, - onTabClick = onTabClick - ) - } - } -} - -@Composable -fun CallsHeader( - onBackClick: () -> Unit, - onCallClick: () -> Unit, - onMenuClick: () -> Unit, - modifier: Modifier = Modifier -) { - Column( - modifier = modifier - .fillMaxWidth() - .height(65.dp) - .border( - width = 1.078.dp, - color = Color(0xFF000000).copy(alpha = 0.1f) - ) - .background(Color(0xFFFCFBF8)) - ) { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 14.dp, vertical = 10.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp) - ) { - Icon( - imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = "Back", - tint = Color(0xFF0A0A0A), - modifier = Modifier - .size(26.dp) - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() } - ) { onBackClick() } - ) - - Text( - text = "Calls", - fontSize = 24.sp, - fontWeight = FontWeight.Medium, - color = Color(0xFF0A0A0A), - lineHeight = 42.sp - ) - } - - Row( - horizontalArrangement = Arrangement.spacedBy(16.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - imageVector = Icons.Default.Phone, - contentDescription = "New Call", - tint = Color(0xFF0A0A0A), - modifier = Modifier - .size(20.dp) - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() } - ) { onCallClick() } - ) - - Icon( - imageVector = Icons.Default.MoreVert, - contentDescription = "Menu", - tint = Color(0xFF0A0A0A), - modifier = Modifier - .size(20.dp) - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() } - ) { onMenuClick() } - ) - } - } - } -} - -@Composable -fun CallHistoryItem( - call: CallRecord, - onClick: () -> Unit, - modifier: Modifier = Modifier -) { - Row( - modifier = modifier - .fillMaxWidth() - .height(76.dp) - .border( - width = 1.078.dp, - color = Color(0xFF000000).copy(alpha = 0.1f), - shape = RoundedCornerShape(12.dp) - ) - .background(Color(0xFFFCFBF8), RoundedCornerShape(12.dp)) - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() } - ) { onClick() } - .padding(horizontal = 16.dp, vertical = 14.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Row( - horizontalArrangement = Arrangement.spacedBy(12.dp), - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.weight(1f) - ) { - Box( - modifier = Modifier - .size(48.dp) - .background(Color(0xFFE5E7EB), CircleShape), - contentAlignment = Alignment.Center - ) { - Text( - text = call.initials, - fontSize = 14.sp, - fontWeight = FontWeight.Medium, - color = Color(0xFF0A0A0A), - lineHeight = 21.sp - ) - } - - Column( - verticalArrangement = Arrangement.spacedBy(4.dp) - ) { - Text( - text = call.name, - fontSize = 16.sp, - fontWeight = FontWeight.Medium, - color = Color(0xFF1E2939), - lineHeight = 20.sp, - letterSpacing = (-0.312).sp - ) - - Row( - horizontalArrangement = Arrangement.spacedBy(8.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - imageVector = when (call.callType) { - CallType.INCOMING -> Icons.AutoMirrored.Filled.CallReceived - CallType.OUTGOING -> Icons.AutoMirrored.Filled.CallMade - CallType.MISSED -> Icons.AutoMirrored.Filled.CallMissed - }, - contentDescription = call.callType.name, - tint = when (call.callType) { - CallType.INCOMING -> Color(0xFF00A63E) - CallType.OUTGOING -> Color(0xFF155DFC) - CallType.MISSED -> Color(0xFFE7000B) - }, - modifier = Modifier.size(20.dp) - ) - - Text( - text = when (call.callType) { - CallType.INCOMING -> "Incoming • ${call.duration}" - CallType.OUTGOING -> "Outgoing • ${call.duration}" - CallType.MISSED -> "Missed" - }, - fontSize = 12.sp, - fontWeight = FontWeight.Normal, - color = Color(0xFF717182), - lineHeight = 16.sp - ) - } - } - } - - Column( - horizontalAlignment = Alignment.End, - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - Text( - text = call.timestamp, - fontSize = 12.sp, - fontWeight = FontWeight.Normal, - color = Color(0xFF717182), - lineHeight = 16.sp - ) - - Icon( - imageVector = if (call.isVideoCall) Icons.Default.Videocam else Icons.Default.Phone, - contentDescription = if (call.isVideoCall) "Video Call" else "Voice Call", - tint = Color(0xFF030213), - modifier = Modifier.size(24.dp) - ) - } - } -} +package com.example.farmmarketplace.ui.screens + +import androidx.compose.foundation.LocalIndication +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.automirrored.filled.CallMade +import androidx.compose.material.icons.automirrored.filled.CallMissed +import androidx.compose.material.icons.automirrored.filled.CallReceived +import androidx.compose.material.icons.filled.* +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.livingai_lg.ui.layout.BottomNavScaffold +import com.example.livingai_lg.ui.models.chatBottomNavItems + +data class CallRecord( + val id: String, + val name: String, + val initials: String, + val callType: CallType, + val duration: String, + val timestamp: String, + val isVideoCall: Boolean = false +) + +enum class CallType { + INCOMING, + OUTGOING, + MISSED +} + +@Composable +fun CallsScreen( + onBackClick: () -> Unit = {}, + onCallClick: () -> Unit = {}, + onMenuClick: () -> Unit = {}, + onCallItemClick: (String) -> Unit = {}, + onTabClick: (route: String) -> Unit = {} +) { + val callHistory = listOf( + CallRecord( + id = "1", + name = "Farmer Kumar", + initials = "FK", + callType = CallType.INCOMING, + duration = "5m 23s", + timestamp = "Today, 2:30 PM" + ), + CallRecord( + id = "2", + name = "Seller Raj", + initials = "SR", + callType = CallType.OUTGOING, + duration = "2m 10s", + timestamp = "Today, 11:45 AM" + ), + CallRecord( + id = "3", + name = "Buyer Priya", + initials = "BP", + callType = CallType.MISSED, + duration = "", + timestamp = "Yesterday, 8:15 PM" + ), + CallRecord( + id = "4", + name = "Seller 1", + initials = "S1", + callType = CallType.OUTGOING, + duration = "8m 45s", + timestamp = "Yesterday, 5:30 PM", + isVideoCall = true + ), + CallRecord( + id = "5", + name = "Veterinarian", + initials = "V", + callType = CallType.INCOMING, + duration = "12m 30s", + timestamp = "2 days ago" + ) + ) + + Box( + modifier = Modifier + .fillMaxSize() + .background(Color(0xFFFCFBF8)) + ) { + BottomNavScaffold( + items = chatBottomNavItems, + currentItem = "Calls", + onBottomNavItemClick = onTabClick, + ) { paddingValues -> + + Column( + modifier = Modifier.fillMaxSize().padding(paddingValues) + ) { + CallsHeader( + onBackClick = onBackClick, + onCallClick = onCallClick, + onMenuClick = onMenuClick + ) + + LazyColumn( + modifier = Modifier + .fillMaxWidth() + .weight(1f) + .padding(horizontal = 16.dp, vertical = 16.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + items(callHistory) { call -> + CallHistoryItem( + call = call, + onClick = { onCallItemClick(call.id) } + ) + } + } + +// ContactsBottomNav( +// currentTab = ContactsTab.CALLS, +// onTabClick = onTabClick +// ) + } + } + } +} + +@Composable +fun CallsHeader( + onBackClick: () -> Unit, + onCallClick: () -> Unit, + onMenuClick: () -> Unit, + modifier: Modifier = Modifier +) { + Column( + modifier = modifier + .fillMaxWidth() + .height(65.dp) + .border( + width = 1.078.dp, + color = Color(0xFF000000).copy(alpha = 0.1f) + ) + .background(Color(0xFFFCFBF8)) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 14.dp, vertical = 10.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = "Back", + tint = Color(0xFF0A0A0A), + modifier = Modifier + .size(26.dp) + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() } + ) { onBackClick() } + ) + + Text( + text = "Calls", + fontSize = 24.sp, + fontWeight = FontWeight.Medium, + color = Color(0xFF0A0A0A), + lineHeight = 42.sp + ) + } + + Row( + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = Icons.Default.Phone, + contentDescription = "New Call", + tint = Color(0xFF0A0A0A), + modifier = Modifier + .size(20.dp) + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() } + ) { onCallClick() } + ) + + Icon( + imageVector = Icons.Default.MoreVert, + contentDescription = "Menu", + tint = Color(0xFF0A0A0A), + modifier = Modifier + .size(20.dp) + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() } + ) { onMenuClick() } + ) + } + } + } +} + +@Composable +fun CallHistoryItem( + call: CallRecord, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + Row( + modifier = modifier + .fillMaxWidth() + .height(76.dp) + .border( + width = 1.078.dp, + color = Color(0xFF000000).copy(alpha = 0.1f), + shape = RoundedCornerShape(12.dp) + ) + .background(Color(0xFFFCFBF8), RoundedCornerShape(12.dp)) + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() } + ) { onClick() } + .padding(horizontal = 16.dp, vertical = 14.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.weight(1f) + ) { + Box( + modifier = Modifier + .size(48.dp) + .background(Color(0xFFE5E7EB), CircleShape), + contentAlignment = Alignment.Center + ) { + Text( + text = call.initials, + fontSize = 14.sp, + fontWeight = FontWeight.Medium, + color = Color(0xFF0A0A0A), + lineHeight = 21.sp + ) + } + + Column( + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + Text( + text = call.name, + fontSize = 16.sp, + fontWeight = FontWeight.Medium, + color = Color(0xFF1E2939), + lineHeight = 20.sp, + letterSpacing = (-0.312).sp + ) + + Row( + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = when (call.callType) { + CallType.INCOMING -> Icons.AutoMirrored.Filled.CallReceived + CallType.OUTGOING -> Icons.AutoMirrored.Filled.CallMade + CallType.MISSED -> Icons.AutoMirrored.Filled.CallMissed + }, + contentDescription = call.callType.name, + tint = when (call.callType) { + CallType.INCOMING -> Color(0xFF00A63E) + CallType.OUTGOING -> Color(0xFF155DFC) + CallType.MISSED -> Color(0xFFE7000B) + }, + modifier = Modifier.size(20.dp) + ) + + Text( + text = when (call.callType) { + CallType.INCOMING -> "Incoming • ${call.duration}" + CallType.OUTGOING -> "Outgoing • ${call.duration}" + CallType.MISSED -> "Missed" + }, + fontSize = 12.sp, + fontWeight = FontWeight.Normal, + color = Color(0xFF717182), + lineHeight = 16.sp + ) + } + } + } + + Column( + horizontalAlignment = Alignment.End, + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text( + text = call.timestamp, + fontSize = 12.sp, + fontWeight = FontWeight.Normal, + color = Color(0xFF717182), + lineHeight = 16.sp + ) + + Icon( + imageVector = if (call.isVideoCall) Icons.Default.Videocam else Icons.Default.Phone, + contentDescription = if (call.isVideoCall) "Video Call" else "Voice Call", + tint = Color(0xFF030213), + modifier = Modifier.size(24.dp) + ) + } + } +} diff --git a/app/src/main/java/com/example/livingai_lg/ui/screens/chat/ChatsScreen.kt b/app/src/main/java/com/example/livingai_lg/ui/screens/chat/ChatsScreen.kt index c1e71f9..42d89ee 100644 --- a/app/src/main/java/com/example/livingai_lg/ui/screens/chat/ChatsScreen.kt +++ b/app/src/main/java/com/example/livingai_lg/ui/screens/chat/ChatsScreen.kt @@ -1,333 +1,341 @@ -package com.example.livingai_lg.ui.screens.chat - -import androidx.compose.foundation.LocalIndication -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.filled.* -import androidx.compose.material3.Icon -import androidx.compose.material3.Text -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import com.example.farmmarketplace.ui.screens.ContactsBottomNav -import com.example.farmmarketplace.ui.screens.ContactsTab - -data class ChatPreview( - val id: String, - val name: String, - val initials: String, - val lastMessage: String, - val timestamp: String, - val isOnline: Boolean = false, - val unreadCount: Int = 0 -) - -@Composable -fun ChatsScreen( - onBackClick: () -> Unit = {}, - onNewChatClick: () -> Unit = {}, - onMenuClick: () -> Unit = {}, - onChatItemClick: (String) -> Unit = {}, - onTabClick: (route: String) -> Unit = {} -) { - val chatList = listOf( - ChatPreview( - id = "1", - name = "Farmer Kumar", - initials = "FK", - lastMessage = "The cows are healthy and ready for viewing", - timestamp = "Today, 2:30 PM", - isOnline = true, - unreadCount = 2 - ), - ChatPreview( - id = "2", - name = "Seller Raj", - initials = "SR", - lastMessage = "You: Can you send more photos?", - timestamp = "Today, 11:45 AM", - isOnline = true, - unreadCount = 0 - ), - ChatPreview( - id = "3", - name = "Buyer Priya", - initials = "BP", - lastMessage = "What's the best time to visit?", - timestamp = "Yesterday, 8:15 PM", - isOnline = false, - unreadCount = 1 - ), - ChatPreview( - id = "4", - name = "Seller 1", - initials = "S1", - lastMessage = "You: Thanks for the information", - timestamp = "Yesterday, 5:30 PM", - isOnline = true, - unreadCount = 0 - ), - ChatPreview( - id = "5", - name = "Veterinarian", - initials = "V", - lastMessage = "The animal health check is complete", - timestamp = "2 days ago", - isOnline = false, - unreadCount = 0 - ), - ChatPreview( - id = "6", - name = "Market Vendor", - initials = "MV", - lastMessage = "You: Available this weekend?", - timestamp = "3 days ago", - isOnline = false, - unreadCount = 0 - ) - ) - - Box( - modifier = Modifier - .fillMaxSize() - .background(Color(0xFFFCFBF8)) - ) { - Column( - modifier = Modifier.fillMaxSize() - ) { - ChatsHeader( - onBackClick = onBackClick, - onNewChatClick = onNewChatClick, - onMenuClick = onMenuClick - ) - - LazyColumn( - modifier = Modifier - .fillMaxWidth() - .weight(1f) - .padding(horizontal = 16.dp, vertical = 16.dp), - verticalArrangement = Arrangement.spacedBy(12.dp) - ) { - items(chatList) { chat -> - ChatListItem( - chat = chat, - onClick = { onChatItemClick(chat.id) } - ) - } - } - - ContactsBottomNav( - currentTab = ContactsTab.CHATS, - onTabClick = onTabClick - ) - } - } -} - -@Composable -fun ChatsHeader( - onBackClick: () -> Unit, - onNewChatClick: () -> Unit, - onMenuClick: () -> Unit, - modifier: Modifier = Modifier -) { - Column( - modifier = modifier - .fillMaxWidth() - .height(65.dp) - .border( - width = 1.078.dp, - color = Color(0xFF000000).copy(alpha = 0.1f) - ) - .background(Color(0xFFFCFBF8)) - ) { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 14.dp, vertical = 10.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp) - ) { - Icon( - imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = "Back", - tint = Color(0xFF0A0A0A), - modifier = Modifier - .size(26.dp) - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() } - ) { onBackClick() } - ) - - Text( - text = "Chats", - fontSize = 24.sp, - fontWeight = FontWeight.Medium, - color = Color(0xFF0A0A0A), - lineHeight = 42.sp - ) - } - - Row( - horizontalArrangement = Arrangement.spacedBy(16.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - imageVector = Icons.Default.Edit, - contentDescription = "New Chat", - tint = Color(0xFF0A0A0A), - modifier = Modifier - .size(20.dp) - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() } - ) { onNewChatClick() } - ) - - Icon( - imageVector = Icons.Default.MoreVert, - contentDescription = "Menu", - tint = Color(0xFF0A0A0A), - modifier = Modifier - .size(20.dp) - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() } - ) { onMenuClick() } - ) - } - } - } -} - -@Composable -fun ChatListItem( - chat: ChatPreview, - onClick: () -> Unit, - modifier: Modifier = Modifier -) { - Row( - modifier = modifier - .fillMaxWidth() - .height(76.dp) - .border( - width = 1.078.dp, - color = Color(0xFF000000).copy(alpha = 0.1f), - shape = RoundedCornerShape(12.dp) - ) - .background(Color(0xFFFCFBF8), RoundedCornerShape(12.dp)) - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() } - ) { onClick() } - .padding(horizontal = 16.dp, vertical = 14.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Row( - horizontalArrangement = Arrangement.spacedBy(12.dp), - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.weight(1f) - ) { - Box( - modifier = Modifier - .size(48.dp) - .background(Color(0xFFE5E7EB), CircleShape), - contentAlignment = Alignment.Center - ) { - Text( - text = chat.initials, - fontSize = 14.sp, - fontWeight = FontWeight.Medium, - color = Color(0xFF0A0A0A), - lineHeight = 21.sp - ) - - if (chat.isOnline) { - Box( - modifier = Modifier - .align(Alignment.BottomEnd) - .size(12.dp) - .background(Color(0xFF00A63E), CircleShape) - .border(2.dp, Color.White, CircleShape) - ) - } - } - - Column( - verticalArrangement = Arrangement.spacedBy(4.dp), - modifier = Modifier.weight(1f) - ) { - Text( - text = chat.name, - fontSize = 16.sp, - fontWeight = FontWeight.Medium, - color = Color(0xFF1E2939), - lineHeight = 20.sp, - letterSpacing = (-0.312).sp - ) - - Text( - text = chat.lastMessage, - fontSize = 12.sp, - fontWeight = FontWeight.Normal, - color = Color(0xFF717182), - lineHeight = 16.sp, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - } - - Column( - horizontalAlignment = Alignment.End, - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - Text( - text = chat.timestamp, - fontSize = 12.sp, - fontWeight = FontWeight.Normal, - color = Color(0xFF717182), - lineHeight = 16.sp - ) - - if (chat.unreadCount > 0) { - Box( - modifier = Modifier - .size(24.dp) - .background(Color(0xFF155DFC), CircleShape), - contentAlignment = Alignment.Center - ) { - Text( - text = chat.unreadCount.toString(), - fontSize = 10.sp, - fontWeight = FontWeight.Medium, - color = Color.White, - lineHeight = 14.sp - ) - } - } - } - } +package com.example.livingai_lg.ui.screens.chat + +import androidx.compose.foundation.LocalIndication +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.filled.* +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.farmmarketplace.ui.screens.ContactsBottomNav +import com.example.farmmarketplace.ui.screens.ContactsTab +import com.example.livingai_lg.ui.layout.BottomNavScaffold +import com.example.livingai_lg.ui.models.chatBottomNavItems + +data class ChatPreview( + val id: String, + val name: String, + val initials: String, + val lastMessage: String, + val timestamp: String, + val isOnline: Boolean = false, + val unreadCount: Int = 0 +) + +@Composable +fun ChatsScreen( + onBackClick: () -> Unit = {}, + onNewChatClick: () -> Unit = {}, + onMenuClick: () -> Unit = {}, + onChatItemClick: (String) -> Unit = {}, + onTabClick: (route: String) -> Unit = {} +) { + val chatList = listOf( + ChatPreview( + id = "1", + name = "Farmer Kumar", + initials = "FK", + lastMessage = "The cows are healthy and ready for viewing", + timestamp = "Today, 2:30 PM", + isOnline = true, + unreadCount = 2 + ), + ChatPreview( + id = "2", + name = "Seller Raj", + initials = "SR", + lastMessage = "You: Can you send more photos?", + timestamp = "Today, 11:45 AM", + isOnline = true, + unreadCount = 0 + ), + ChatPreview( + id = "3", + name = "Buyer Priya", + initials = "BP", + lastMessage = "What's the best time to visit?", + timestamp = "Yesterday, 8:15 PM", + isOnline = false, + unreadCount = 1 + ), + ChatPreview( + id = "4", + name = "Seller 1", + initials = "S1", + lastMessage = "You: Thanks for the information", + timestamp = "Yesterday, 5:30 PM", + isOnline = true, + unreadCount = 0 + ), + ChatPreview( + id = "5", + name = "Veterinarian", + initials = "V", + lastMessage = "The animal health check is complete", + timestamp = "2 days ago", + isOnline = false, + unreadCount = 0 + ), + ChatPreview( + id = "6", + name = "Market Vendor", + initials = "MV", + lastMessage = "You: Available this weekend?", + timestamp = "3 days ago", + isOnline = false, + unreadCount = 0 + ) + ) + + Box( + modifier = Modifier + .fillMaxSize() + .background(Color(0xFFFCFBF8)) + ) { + BottomNavScaffold( + items = chatBottomNavItems, + currentItem = "Chats", + onBottomNavItemClick = onTabClick, + ) { paddingValues -> + Column( + modifier = Modifier.fillMaxSize().padding(paddingValues) + ) { + ChatsHeader( + onBackClick = onBackClick, + onNewChatClick = onNewChatClick, + onMenuClick = onMenuClick + ) + + LazyColumn( + modifier = Modifier + .fillMaxWidth() + .weight(1f) + .padding(horizontal = 16.dp, vertical = 16.dp), + verticalArrangement = Arrangement.spacedBy(12.dp) + ) { + items(chatList) { chat -> + ChatListItem( + chat = chat, + onClick = { onChatItemClick(chat.id) } + ) + } + } + +// ContactsBottomNav( +// currentTab = ContactsTab.CHATS, +// onTabClick = onTabClick +// ) + } + } + } +} + +@Composable +fun ChatsHeader( + onBackClick: () -> Unit, + onNewChatClick: () -> Unit, + onMenuClick: () -> Unit, + modifier: Modifier = Modifier +) { + Column( + modifier = modifier + .fillMaxWidth() + .height(65.dp) + .border( + width = 1.078.dp, + color = Color(0xFF000000).copy(alpha = 0.1f) + ) + .background(Color(0xFFFCFBF8)) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 14.dp, vertical = 10.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = "Back", + tint = Color(0xFF0A0A0A), + modifier = Modifier + .size(26.dp) + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() } + ) { onBackClick() } + ) + + Text( + text = "Chats", + fontSize = 24.sp, + fontWeight = FontWeight.Medium, + color = Color(0xFF0A0A0A), + lineHeight = 42.sp + ) + } + + Row( + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = Icons.Default.Edit, + contentDescription = "New Chat", + tint = Color(0xFF0A0A0A), + modifier = Modifier + .size(20.dp) + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() } + ) { onNewChatClick() } + ) + + Icon( + imageVector = Icons.Default.MoreVert, + contentDescription = "Menu", + tint = Color(0xFF0A0A0A), + modifier = Modifier + .size(20.dp) + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() } + ) { onMenuClick() } + ) + } + } + } +} + +@Composable +fun ChatListItem( + chat: ChatPreview, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + Row( + modifier = modifier + .fillMaxWidth() + .height(76.dp) + .border( + width = 1.078.dp, + color = Color(0xFF000000).copy(alpha = 0.1f), + shape = RoundedCornerShape(12.dp) + ) + .background(Color(0xFFFCFBF8), RoundedCornerShape(12.dp)) + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() } + ) { onClick() } + .padding(horizontal = 16.dp, vertical = 14.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.weight(1f) + ) { + Box( + modifier = Modifier + .size(48.dp) + .background(Color(0xFFE5E7EB), CircleShape), + contentAlignment = Alignment.Center + ) { + Text( + text = chat.initials, + fontSize = 14.sp, + fontWeight = FontWeight.Medium, + color = Color(0xFF0A0A0A), + lineHeight = 21.sp + ) + + if (chat.isOnline) { + Box( + modifier = Modifier + .align(Alignment.BottomEnd) + .size(12.dp) + .background(Color(0xFF00A63E), CircleShape) + .border(2.dp, Color.White, CircleShape) + ) + } + } + + Column( + verticalArrangement = Arrangement.spacedBy(4.dp), + modifier = Modifier.weight(1f) + ) { + Text( + text = chat.name, + fontSize = 16.sp, + fontWeight = FontWeight.Medium, + color = Color(0xFF1E2939), + lineHeight = 20.sp, + letterSpacing = (-0.312).sp + ) + + Text( + text = chat.lastMessage, + fontSize = 12.sp, + fontWeight = FontWeight.Normal, + color = Color(0xFF717182), + lineHeight = 16.sp, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + } + + Column( + horizontalAlignment = Alignment.End, + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text( + text = chat.timestamp, + fontSize = 12.sp, + fontWeight = FontWeight.Normal, + color = Color(0xFF717182), + lineHeight = 16.sp + ) + + if (chat.unreadCount > 0) { + Box( + modifier = Modifier + .size(24.dp) + .background(Color(0xFF155DFC), CircleShape), + contentAlignment = Alignment.Center + ) { + Text( + text = chat.unreadCount.toString(), + fontSize = 10.sp, + fontWeight = FontWeight.Medium, + color = Color.White, + lineHeight = 14.sp + ) + } + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/livingai_lg/ui/screens/chat/ContactsScreen.kt b/app/src/main/java/com/example/livingai_lg/ui/screens/chat/ContactsScreen.kt index 6dc9b5f..9b5e873 100644 --- a/app/src/main/java/com/example/livingai_lg/ui/screens/chat/ContactsScreen.kt +++ b/app/src/main/java/com/example/livingai_lg/ui/screens/chat/ContactsScreen.kt @@ -1,422 +1,432 @@ -package com.example.farmmarketplace.ui.screens - -import androidx.compose.foundation.LocalIndication -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.automirrored.filled.Chat -import androidx.compose.material.icons.automirrored.filled.Message -import androidx.compose.material.icons.automirrored.outlined.Message -import androidx.compose.material.icons.filled.Chat -import androidx.compose.material.icons.filled.Contacts -import androidx.compose.material.icons.filled.Message -import androidx.compose.material.icons.filled.MoreVert -import androidx.compose.material.icons.filled.Phone -import androidx.compose.material.icons.filled.Search -import androidx.compose.material.icons.outlined.Phone -import androidx.compose.material3.Icon -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.graphics.vector.path -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import com.example.livingai_lg.ui.navigation.AppScreen - -data class Contact( - val id: String, - val name: String, - val initials: String, - val status: String, - val isOnline: Boolean = false, - val phoneNumber: String? = null -) - -enum class ContactsTab { - CONTACTS, - CALLS, - CHATS -} - -@Composable -fun ContactsScreen( - onBackClick: () -> Unit = {}, - onSearchClick: () -> Unit = {}, - onMenuClick: () -> Unit = {}, - onContactClick: (String) -> Unit = {}, - onCallClick: (String) -> Unit = {}, - onMessageClick: (String) -> Unit = {}, - onTabClick: (route: String) -> Unit = {} -) { - val contacts = listOf( - Contact( - id = "1", - name = "Farmer Kumar", - initials = "FK", - status = "Online", - isOnline = true - ), - Contact( - id = "2", - name = "Seller Raj", - initials = "SR", - status = "+91 98765 43211", - isOnline = false, - phoneNumber = "+91 98765 43211" - ), - Contact( - id = "3", - name = "Buyer Priya", - initials = "BP", - status = "Online", - isOnline = true - ), - Contact( - id = "4", - name = "Seller 1", - initials = "S1", - status = "+91 98765 43213", - isOnline = false, - phoneNumber = "+91 98765 43213" - ), - Contact( - id = "5", - name = "Veterinarian", - initials = "V", - status = "Online", - isOnline = true - ), - Contact( - id = "6", - name = "Farm Supply", - initials = "FS", - status = "+91 98765 43215", - isOnline = false, - phoneNumber = "+91 98765 43215" - ), - Contact( - id = "7", - name = "Transport Co.", - initials = "TC", - status = "+91 98765 43216", - isOnline = false, - phoneNumber = "+91 98765 43216" - ) - ) - - Box( - modifier = Modifier - .fillMaxSize() - .background(Color(0xFFFCFBF8)) - ) { - Column( - modifier = Modifier.fillMaxSize() - ) { - ContactsHeader( - onBackClick = onBackClick, - onSearchClick = onSearchClick, - onMenuClick = onMenuClick - ) - - LazyColumn( - modifier = Modifier - .fillMaxWidth() - .weight(1f) - ) { - items(contacts) { contact -> - ContactItem( - contact = contact, - onContactClick = { onContactClick(contact.id) }, - onCallClick = { onCallClick(contact.id) }, - onMessageClick = { onMessageClick(contact.id) } - ) - } - } - - ContactsBottomNav( - currentTab = ContactsTab.CONTACTS, - onTabClick = onTabClick - ) - } - } -} - -@Composable -fun ContactsHeader( - onBackClick: () -> Unit, - onSearchClick: () -> Unit, - onMenuClick: () -> Unit, - modifier: Modifier = Modifier -) { - Column( - modifier = modifier - .fillMaxWidth() - .height(65.dp) - .border( - width = 1.078.dp, - color = Color(0xFF000000).copy(alpha = 0.1f) - ) - .background(Color(0xFFFCFBF8)) - ) { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 12.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp) - ) { - Icon( - imageVector = Icons.AutoMirrored.Default.ArrowBack, - contentDescription = "Back", - tint = Color(0xFF0A0A0A), - modifier = Modifier - .size(26.dp) - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() } - ) { onBackClick() } - ) - - Text( - text = "Contacts", - fontSize = 24.sp, - fontWeight = FontWeight.Medium, - color = Color(0xFF0A0A0A), - lineHeight = 42.sp - ) - } - - Row( - horizontalArrangement = Arrangement.spacedBy(16.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - imageVector = Icons.Default.Search, - contentDescription = "Search", - tint = Color(0xFF0A0A0A), - modifier = Modifier - .size(20.dp) - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() } - ) { onSearchClick() } - ) - - Icon( - imageVector = Icons.Default.MoreVert, - contentDescription = "Menu", - tint = Color(0xFF0A0A0A), - modifier = Modifier - .size(20.dp) - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() } - ) { onMenuClick() } - ) - } - } - } -} - -@Composable -fun ContactItem( - contact: Contact, - onContactClick: () -> Unit, - onCallClick: () -> Unit, - onMessageClick: () -> Unit, - modifier: Modifier = Modifier -) { - Row( - modifier = modifier - .fillMaxWidth() - .height(73.dp) - .border( - width = 1.078.dp, - color = Color(0xFF000000).copy(alpha = 0.05f) - ) - .background(Color(0xFFFCFBF8)) - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() } - ) { onContactClick() } - .padding(horizontal = 16.dp, vertical = 12.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Row( - horizontalArrangement = Arrangement.spacedBy(12.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier - .size(48.dp) - .background(Color(0xFFE5E7EB), CircleShape), - contentAlignment = Alignment.Center - ) { - Text( - text = contact.initials, - fontSize = 14.sp, - fontWeight = FontWeight.Medium, - color = Color(0xFF0A0A0A), - lineHeight = 21.sp - ) - } - - Column( - verticalArrangement = Arrangement.spacedBy(4.dp) - ) { - Text( - text = contact.name, - fontSize = 16.sp, - fontWeight = FontWeight.Medium, - color = Color(0xFF1E2939), - lineHeight = 20.sp, - letterSpacing = (-0.312).sp - ) - - Text( - text = contact.status, - fontSize = 12.sp, - fontWeight = FontWeight.Normal, - color = Color(0xFF717182), - lineHeight = 16.sp - ) - } - } - - Row( - horizontalArrangement = Arrangement.spacedBy(12.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier - .size(36.dp) - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() } - ) { onCallClick() }, - contentAlignment = Alignment.Center - ) { - Icon( - imageVector = Icons.Outlined.Phone, - contentDescription = "Call", - tint = Color(0xFF030213), - modifier = Modifier.size(20.dp) - ) - } - - Box( - modifier = Modifier - .size(36.dp) - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() } - ) { onMessageClick() }, - contentAlignment = Alignment.Center - ) { - Icon( - imageVector = Icons.AutoMirrored.Outlined.Message, - contentDescription = "Message", - tint = Color(0xFF030213), - modifier = Modifier.size(20.dp) - ) - } - } - } -} - -@Composable -fun ContactsBottomNav( - currentTab: ContactsTab, - onTabClick: (route: String) -> Unit, - modifier: Modifier = Modifier -) { - Row( - modifier = modifier - .fillMaxWidth() - .height(65.dp) - .border( - width = 1.078.dp, - color = Color(0xFF000000).copy(alpha = 0.1f) - ) - .background(Color(0xFFFCFBF8)) - .padding(horizontal = 32.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - - ContactsTabItem( - icon = Icons.AutoMirrored.Filled.Chat, - label = "Chats", - isSelected = currentTab == ContactsTab.CHATS, - onClick = { onTabClick(AppScreen.CHATS) } - ) - ContactsTabItem( - icon = Icons.Default.Phone, - label = "Calls", - isSelected = currentTab == ContactsTab.CALLS, - onClick = { onTabClick(AppScreen.CALLS) } - ) - ContactsTabItem( - icon = Icons.Default.Contacts, - label = "Contacts", - isSelected = currentTab == ContactsTab.CONTACTS, - onClick = { onTabClick(AppScreen.CONTACTS) } - ) - - - } -} - -@Composable -fun ContactsTabItem( - icon: ImageVector, - label: String, - isSelected: Boolean, - onClick: () -> Unit, - modifier: Modifier = Modifier -) { - Column( - modifier = modifier - .clickable( - indication = LocalIndication.current, - interactionSource = remember { MutableInteractionSource() } - ) { onClick() } - .padding(4.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(4.dp) - ) { - Icon( - imageVector = icon, - contentDescription = label, - tint = Color(0xFF0A0A0A), - modifier = Modifier.size(24.dp) - ) - - Text( - text = label, - fontSize = 12.sp, - fontWeight = FontWeight.Medium, - color = Color(0xFF0A0A0A), - lineHeight = 16.sp, - textAlign = TextAlign.Center - ) - } +package com.example.farmmarketplace.ui.screens + +import androidx.compose.foundation.LocalIndication +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.automirrored.filled.Chat +import androidx.compose.material.icons.automirrored.filled.Message +import androidx.compose.material.icons.automirrored.outlined.Message +import androidx.compose.material.icons.filled.Chat +import androidx.compose.material.icons.filled.Contacts +import androidx.compose.material.icons.filled.Message +import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.material.icons.filled.Phone +import androidx.compose.material.icons.filled.Search +import androidx.compose.material.icons.outlined.Phone +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.example.livingai_lg.ui.layout.BottomNavScaffold +import com.example.livingai_lg.ui.models.chatBottomNavItems +import com.example.livingai_lg.ui.models.mainBottomNavItems +import com.example.livingai_lg.ui.navigation.AppScreen + +data class Contact( + val id: String, + val name: String, + val initials: String, + val status: String, + val isOnline: Boolean = false, + val phoneNumber: String? = null +) + +enum class ContactsTab { + CONTACTS, + CALLS, + CHATS +} + +@Composable +fun ContactsScreen( + onBackClick: () -> Unit = {}, + onSearchClick: () -> Unit = {}, + onMenuClick: () -> Unit = {}, + onContactClick: (String) -> Unit = {}, + onCallClick: (String) -> Unit = {}, + onMessageClick: (String) -> Unit = {}, + onTabClick: (route: String) -> Unit = {} +) { + val contacts = listOf( + Contact( + id = "1", + name = "Farmer Kumar", + initials = "FK", + status = "Online", + isOnline = true + ), + Contact( + id = "2", + name = "Seller Raj", + initials = "SR", + status = "+91 98765 43211", + isOnline = false, + phoneNumber = "+91 98765 43211" + ), + Contact( + id = "3", + name = "Buyer Priya", + initials = "BP", + status = "Online", + isOnline = true + ), + Contact( + id = "4", + name = "Seller 1", + initials = "S1", + status = "+91 98765 43213", + isOnline = false, + phoneNumber = "+91 98765 43213" + ), + Contact( + id = "5", + name = "Veterinarian", + initials = "V", + status = "Online", + isOnline = true + ), + Contact( + id = "6", + name = "Farm Supply", + initials = "FS", + status = "+91 98765 43215", + isOnline = false, + phoneNumber = "+91 98765 43215" + ), + Contact( + id = "7", + name = "Transport Co.", + initials = "TC", + status = "+91 98765 43216", + isOnline = false, + phoneNumber = "+91 98765 43216" + ) + ) + + Box( + modifier = Modifier + .fillMaxSize() + .background(Color(0xFFFCFBF8)) + ) { + BottomNavScaffold( + items = chatBottomNavItems, + currentItem = "Contacts", + onBottomNavItemClick = onTabClick, + ) { paddingValues -> + + Column( + modifier = Modifier.fillMaxSize().padding(paddingValues) + ) { + ContactsHeader( + onBackClick = onBackClick, + onSearchClick = onSearchClick, + onMenuClick = onMenuClick + ) + + LazyColumn( + modifier = Modifier + .fillMaxWidth() + .weight(1f) + ) { + items(contacts) { contact -> + ContactItem( + contact = contact, + onContactClick = { onContactClick(contact.id) }, + onCallClick = { onCallClick(contact.id) }, + onMessageClick = { onMessageClick(contact.id) } + ) + } + } + +// ContactsBottomNav( +// currentTab = ContactsTab.CONTACTS, +// onTabClick = onTabClick +// ) + } + } + } +} + +@Composable +fun ContactsHeader( + onBackClick: () -> Unit, + onSearchClick: () -> Unit, + onMenuClick: () -> Unit, + modifier: Modifier = Modifier +) { + Column( + modifier = modifier + .fillMaxWidth() + .height(65.dp) + .border( + width = 1.078.dp, + color = Color(0xFF000000).copy(alpha = 0.1f) + ) + .background(Color(0xFFFCFBF8)) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 12.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + Icon( + imageVector = Icons.AutoMirrored.Default.ArrowBack, + contentDescription = "Back", + tint = Color(0xFF0A0A0A), + modifier = Modifier + .size(26.dp) + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() } + ) { onBackClick() } + ) + + Text( + text = "Contacts", + fontSize = 24.sp, + fontWeight = FontWeight.Medium, + color = Color(0xFF0A0A0A), + lineHeight = 42.sp + ) + } + + Row( + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = Icons.Default.Search, + contentDescription = "Search", + tint = Color(0xFF0A0A0A), + modifier = Modifier + .size(20.dp) + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() } + ) { onSearchClick() } + ) + + Icon( + imageVector = Icons.Default.MoreVert, + contentDescription = "Menu", + tint = Color(0xFF0A0A0A), + modifier = Modifier + .size(20.dp) + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() } + ) { onMenuClick() } + ) + } + } + } +} + +@Composable +fun ContactItem( + contact: Contact, + onContactClick: () -> Unit, + onCallClick: () -> Unit, + onMessageClick: () -> Unit, + modifier: Modifier = Modifier +) { + Row( + modifier = modifier + .fillMaxWidth() + .height(73.dp) + .border( + width = 1.078.dp, + color = Color(0xFF000000).copy(alpha = 0.05f) + ) + .background(Color(0xFFFCFBF8)) + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() } + ) { onContactClick() } + .padding(horizontal = 16.dp, vertical = 12.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .size(48.dp) + .background(Color(0xFFE5E7EB), CircleShape), + contentAlignment = Alignment.Center + ) { + Text( + text = contact.initials, + fontSize = 14.sp, + fontWeight = FontWeight.Medium, + color = Color(0xFF0A0A0A), + lineHeight = 21.sp + ) + } + + Column( + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + Text( + text = contact.name, + fontSize = 16.sp, + fontWeight = FontWeight.Medium, + color = Color(0xFF1E2939), + lineHeight = 20.sp, + letterSpacing = (-0.312).sp + ) + + Text( + text = contact.status, + fontSize = 12.sp, + fontWeight = FontWeight.Normal, + color = Color(0xFF717182), + lineHeight = 16.sp + ) + } + } + + Row( + horizontalArrangement = Arrangement.spacedBy(12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .size(36.dp) + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() } + ) { onCallClick() }, + contentAlignment = Alignment.Center + ) { + Icon( + imageVector = Icons.Outlined.Phone, + contentDescription = "Call", + tint = Color(0xFF030213), + modifier = Modifier.size(20.dp) + ) + } + + Box( + modifier = Modifier + .size(36.dp) + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() } + ) { onMessageClick() }, + contentAlignment = Alignment.Center + ) { + Icon( + imageVector = Icons.AutoMirrored.Outlined.Message, + contentDescription = "Message", + tint = Color(0xFF030213), + modifier = Modifier.size(20.dp) + ) + } + } + } +} + +@Composable +fun ContactsBottomNav( + currentTab: ContactsTab, + onTabClick: (route: String) -> Unit, + modifier: Modifier = Modifier +) { + Row( + modifier = modifier + .fillMaxWidth() + .height(65.dp) + .border( + width = 1.078.dp, + color = Color(0xFF000000).copy(alpha = 0.1f) + ) + .background(Color(0xFFFCFBF8)) + .padding(horizontal = 32.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + + ContactsTabItem( + icon = Icons.AutoMirrored.Filled.Chat, + label = "Chats", + isSelected = currentTab == ContactsTab.CHATS, + onClick = { onTabClick(AppScreen.CHATS) } + ) + ContactsTabItem( + icon = Icons.Default.Phone, + label = "Calls", + isSelected = currentTab == ContactsTab.CALLS, + onClick = { onTabClick(AppScreen.CALLS) } + ) + ContactsTabItem( + icon = Icons.Default.Contacts, + label = "Contacts", + isSelected = currentTab == ContactsTab.CONTACTS, + onClick = { onTabClick(AppScreen.CONTACTS) } + ) + + + } +} + +@Composable +fun ContactsTabItem( + icon: ImageVector, + label: String, + isSelected: Boolean, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + Column( + modifier = modifier + .clickable( + indication = LocalIndication.current, + interactionSource = remember { MutableInteractionSource() } + ) { onClick() } + .padding(4.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + Icon( + imageVector = icon, + contentDescription = label, + tint = Color(0xFF0A0A0A), + modifier = Modifier.size(24.dp) + ) + + Text( + text = label, + fontSize = 12.sp, + fontWeight = FontWeight.Medium, + color = Color(0xFF0A0A0A), + lineHeight = 16.sp, + textAlign = TextAlign.Center + ) + } } \ No newline at end of file