This is a dating app
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

327 lines
13 KiB

package com.example.dattingapp
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.LocationOn
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage
import com.example.dattingapp.homes.networkandapi.LikedUiState
import com.example.dattingapp.homes.networkandapi.LikedViewModel
import com.example.dattingapp.homes.profile.LikedUserResponse
import com.example.dattingapp.ui.theme.DattingAPPTheme
import java.time.LocalDate
import java.time.Period
import java.time.format.DateTimeFormatter
class LikeANdMatchActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
DattingAPPTheme {
val likedViewModel: LikedViewModel = viewModel()
val context = LocalContext.current
val type = intent.getStringExtra("TYPE") ?: "Likes"
val uiState by when (type) {
"Likes" -> likedViewModel.likesUiState.collectAsState()
"Liked" -> likedViewModel.likedUiState.collectAsState()
else -> likedViewModel.matchesUiState.collectAsState()
}
LaunchedEffect(Unit) {
likedViewModel.likedResponse(context, type)
}
Scaffold(
modifier = Modifier.fillMaxSize(),
topBar = {
@OptIn(ExperimentalMaterial3Api::class)
TopAppBar(
title = {
Text(
text = when (type) {
"Likes" -> "My Likes"
"Liked" -> "Liked Me"
else -> "My Matches"
},
fontWeight = FontWeight.Bold,
fontSize = 18.sp
)
},
navigationIcon = {
IconButton(onClick = { finish() }) {
Icon(
imageVector = Icons.Default.ArrowBack,
contentDescription = "Back"
)
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.surface
)
)
}
) { innerPadding ->
Box(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding),
contentAlignment = Alignment.Center
) {
when (val state = uiState) {
is LikedUiState.Idle, is LikedUiState.Loading -> {
CircularProgressIndicator()
}
is LikedUiState.Success -> {
ProfileGrid(
context = context,
likedResponse = state.LikeData,
isLoading = false,
errorMessage = null
)
}
is LikedUiState.Error -> {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.padding(16.dp)
) {
Text(
text = state.message,
color = MaterialTheme.colorScheme.error,
fontWeight = FontWeight.Medium
)
Button(onClick = { likedViewModel.likedResponse(context, type) }) {
Text("Retry")
}
}
}
}
}
}
}
}
}
}
@Composable
fun ProfileCard(
context: Context,
likedProfile: LikedUserResponse,
modifier: Modifier = Modifier,
onNameClick: () -> Unit = {},
) {
Card(
shape = RoundedCornerShape(16.dp),
colors = CardDefaults.cardColors(containerColor = Color.White),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp),
modifier = modifier.fillMaxWidth()
) {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(180.dp)
.clip(RoundedCornerShape(12.dp))
.clickable {
val intent = Intent(context, FriendProfile::class.java).apply {
putExtra("USER_ID", likedProfile.id)
}
context.startActivity(intent)
onNameClick()
}
) {
// FIX: media can be null from the server, so use ?. here
AsyncImage(
model = likedProfile.profile_image_url?.takeIf { it.isNotBlank() }
?: likedProfile.media?.firstOrNull(),
contentDescription = likedProfile.full_name,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
Box(
modifier = Modifier
.fillMaxSize()
.background(
Brush.verticalGradient(
colors = listOf(Color.Transparent, Color.Black.copy(alpha = 0.7f)),
startY = 100f
)
)
)
Surface(
shape = RoundedCornerShape(20.dp),
color = Color.White.copy(alpha = 0.9f),
modifier = Modifier
.padding(8.dp)
.align(Alignment.TopStart)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp),
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)
) {
Icon(
imageVector = Icons.Default.Favorite,
contentDescription = null,
tint = Color(0xFF6C5CE7),
modifier = Modifier.size(12.dp)
)
Text(
text = "${likedProfile.compatibility_percentage ?: 0}%",
fontSize = 11.sp,
fontWeight = FontWeight.Bold,
color = Color(0xFF2D3436)
)
}
}
Column(
modifier = Modifier
.align(Alignment.BottomStart)
.padding(8.dp)
) {
val displayName = likedProfile.full_name?.ifBlank { "User" } ?: "User"
val age = remember(likedProfile.birth_date) {
calculateAge(likedProfile.birth_date)
}
val nameAndAge = if (age != null) "$displayName, $age" else displayName
Log.d("user", "${likedProfile.id}")
Text(
text = nameAndAge,
color = Color.White,
fontWeight = FontWeight.Bold,
fontSize = 14.sp
)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(2.dp)
) {
Icon(
imageVector = Icons.Default.LocationOn,
contentDescription = null,
tint = Color.White.copy(alpha = 0.8f),
modifier = Modifier.size(10.dp)
)
Text(
text = "${likedProfile.distance_km ?: 0.0} km",
color = Color.White.copy(alpha = 0.8f),
fontSize = 10.sp
)
}
}
}
}
}
}
@Composable
fun ProfileGrid(
context: Context,
likedResponse: List<LikedUserResponse>,
isLoading: Boolean,
errorMessage: String?,
onRetry: () -> Unit = {},
modifier: Modifier = Modifier
) {
if (likedResponse.isEmpty() && !isLoading) {
Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text("No profiles found.", color = Color.Gray)
}
return
}
LazyVerticalGrid(
columns = GridCells.Fixed(2),
contentPadding = PaddingValues(12.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalArrangement = Arrangement.spacedBy(12.dp),
modifier = modifier.fillMaxSize()
) {
items(likedResponse) { profile ->
ProfileCard(context, likedProfile = profile)
}
}
}
private fun calculateAge(birthDateStr: String?): Int? {
if (birthDateStr.isNullOrBlank()) return null
return try {
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
val birthDate = LocalDate.parse(birthDateStr.take(10), formatter)
Period.between(birthDate, LocalDate.now()).years
} catch (e: Exception) {
null
}
}
@Preview(showBackground = true)
@Composable
fun ProfileGridPreview() {
val sampleLikedUsers = listOf(
LikedUserResponse(
id = 55,
full_name = "Sarah Jenkins",
gender = "female",
birth_date = "1995-08-20",
city = "Shanghai",
county = "District A",
country = "China",
relationship_goal = "dating",
bio = "Coffee lover and traveler.",
profile_image_url = "",
video_url = null,
distance_km = 4.1,
compatibility_percentage = 92,
media = emptyList()
)
)
val context = LocalContext.current
DattingAPPTheme {
ProfileGrid(
context = context,
likedResponse = sampleLikedUsers,
isLoading = false,
errorMessage = null
)
}
}