diff --git a/app/src/main/java/com/example/dattingapp/FriendProfile.kt b/app/src/main/java/com/example/dattingapp/FriendProfile.kt index 0f05455..2ac0b34 100644 --- a/app/src/main/java/com/example/dattingapp/FriendProfile.kt +++ b/app/src/main/java/com/example/dattingapp/FriendProfile.kt @@ -51,6 +51,7 @@ import com.example.dattingapp.homes.profile.FrienPostMedia import com.example.dattingapp.homes.profile.FriendAuthor import com.example.dattingapp.homes.profile.FriendPost import com.example.dattingapp.homes.profile.FriendProfileResponse +import com.example.dattingapp.homes.profile.LikedUserResponse import com.example.dattingapp.ui.theme.* import java.time.LocalDate import java.time.Period @@ -82,6 +83,9 @@ class FriendProfile : ComponentActivity() { } } + + + when (val state = profileUiState) { is FriendProfileUiState.Loading -> { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { @@ -120,6 +124,36 @@ fun FriendProfileScreen( onStarClick: () -> Unit = {}, onCancelClick: () -> Unit = {} ) { + + val likedViewModel: LikedViewModel = viewModel() + + // ✅ collect each state separately + val likesState by likedViewModel.likesUiState.collectAsState() // who liked me + val likedState by likedViewModel.likedUiState.collectAsState() // I liked + val matchesState by likedViewModel.matchesUiState.collectAsState() // matches + + // ✅ load all three lists once + LaunchedEffect(Unit) { + likedViewModel.likedResponse(context, "Likes") + likedViewModel.likedResponse(context, "Liked") + likedViewModel.likedResponse(context, "Matches") + } + + // ✅ turn each into a set of ids + val likedMeIds = (likesState as? LikedUiState.Success) + ?.LikeData?.map { it.id }?.toSet() ?: emptySet() + + val iLikedIds = (likedState as? LikedUiState.Success) + ?.LikeData?.map { it.id }?.toSet() ?: emptySet() + + val matchIds = (matchesState as? LikedUiState.Success) + ?.LikeData?.map { it.id }?.toSet() ?: emptySet() + + // ✅ the three booleans for the button row + val isMatch = friendProfileData.id in matchIds + val heLikedMe = friendProfileData.id in likedMeIds + val iLikedHim = friendProfileData.id in iLikedIds + val age = remember(friendProfileData.birth_date) { calculateAge(friendProfileData.birth_date) } @@ -269,6 +303,7 @@ fun FriendProfileScreen( ) } + // Action Buttons Row Row( modifier = Modifier @@ -277,86 +312,110 @@ fun FriendProfileScreen( horizontalArrangement = Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.CenterVertically ) { - Button( - onClick = onMessageClick, - modifier = Modifier - .weight(1f) - .height(48.dp) - .background( - brush = gradientBrush, - shape = RoundedCornerShape(10.dp) - ), - colors = ButtonDefaults.buttonColors( - containerColor = Color.Transparent, - contentColor = Color.White - ), - shape = RoundedCornerShape(10.dp) - ) { - Icon( - imageVector = Icons.Default.ChatBubble, - contentDescription = "Message", - modifier = Modifier.size(18.dp) - ) - Spacer(modifier = Modifier.width(8.dp)) - Text( - text = "Message", - fontSize = 16.sp, - fontWeight = FontWeight.Bold - ) + // Message — inside a card + if (isMatch) { + Card( + onClick = onMessageClick, + modifier = Modifier + .weight(1f) + .height(48.dp), + shape = RoundedCornerShape(10.dp), + colors = CardDefaults.cardColors(containerColor = Color.White), + elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) + ) { + Row( + modifier = Modifier.fillMaxSize(), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = Icons.Default.ChatBubble, + contentDescription = "Message", + tint = textDark, + modifier = Modifier.size(18.dp) + ) + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = "Message", + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + color = textDark + ) + } + } } - IconButton( - onClick = { - onLikeClick() - handleLikeAndDislikeAction(context, "right", friendProfileData, swipeViewModel) - }, - modifier = Modifier - .size(48.dp) - .background(color = purpleButtonColor, shape = RoundedCornerShape(10.dp)) - ) { - Icon( - imageVector = Icons.Default.Favorite, - contentDescription = "Like", - tint = Color(0xFFE2C4FF), - modifier = Modifier.size(20.dp) - ) - } + // ❤️ Like — red ICON when the user liked ME, hidden when matched + if (!isMatch) { + Card( + onClick = { + onLikeClick() + handleLikeAndDislikeAction(context, "right", friendProfileData, swipeViewModel) + }, + modifier = Modifier.size(48.dp), + shape = RoundedCornerShape(10.dp), + colors = CardDefaults.cardColors(containerColor = Color.White), + elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) + ) { + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Icon( + imageVector = Icons.Default.Favorite, + contentDescription = "Like", + tint = when { + heLikedMe -> Color(0xFFE53935) // 🔴 user liked me + iLikedHim -> Color(0xFF1E88E5) // 🔵 I liked the user + else -> textDark // ⚫ no relation yet + }, + modifier = Modifier.size(22.dp) + ) + } + } - IconButton( - onClick = { - onStarClick() - handleLikeAndDislikeAction(context, "right", friendProfileData, swipeViewModel) - }, - modifier = Modifier - .size(48.dp) - .background(color = purpleButtonColor, shape = RoundedCornerShape(10.dp)) - ) { - Icon( - imageVector = Icons.Default.Star, - contentDescription = "Favorite", - tint = Color(0xFFE2C4FF), - modifier = Modifier.size(20.dp) - ) + // Super Like — inside a card + Card( + onClick = { + onStarClick() + handleLikeAndDislikeAction(context, "right", friendProfileData, swipeViewModel) + }, + modifier = Modifier.size(48.dp), + shape = RoundedCornerShape(10.dp), + colors = CardDefaults.cardColors(containerColor = Color.White), + elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) + ) { + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Icon( + imageVector = Icons.Default.Star, + contentDescription = "Favorite", + tint = textDark, + modifier = Modifier.size(22.dp) + ) + } + } } - IconButton( + // Cancel — inside a card, always visible + Card( onClick = { onCancelClick() handleLikeAndDislikeAction(context, "left", friendProfileData, swipeViewModel) }, - modifier = Modifier - .size(48.dp) - .background(color = purpleButtonColor, shape = RoundedCornerShape(10.dp)) + modifier = Modifier.size(48.dp), + shape = RoundedCornerShape(10.dp), + colors = CardDefaults.cardColors(containerColor = Color.White), + elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) ) { - Icon( - imageVector = Icons.Default.Close, - contentDescription = "Dislike", - tint = Color(0xFFE2C4FF), - modifier = Modifier.size(20.dp) - ) + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Icon( + imageVector = Icons.Default.Close, + contentDescription = "Dislike", + tint = textDark, + modifier = Modifier.size(22.dp) + ) + } } } + Spacer(modifier = Modifier.height(16.dp)) // User Posts Grid Section below Action Row diff --git a/app/src/main/java/com/example/dattingapp/LikeANdMatchActivity.kt b/app/src/main/java/com/example/dattingapp/LikeANdMatchActivity.kt index 931d878..7b54302 100644 --- a/app/src/main/java/com/example/dattingapp/LikeANdMatchActivity.kt +++ b/app/src/main/java/com/example/dattingapp/LikeANdMatchActivity.kt @@ -54,13 +54,14 @@ class LikeANdMatchActivity : ComponentActivity() { DattingAPPTheme { val likedViewModel: LikedViewModel = viewModel() val context = LocalContext.current + val type = intent.getStringExtra("TYPE") ?: "liked" // Collect state from ViewModel - val uiState by likedViewModel.likeUiState.collectAsState() + val uiState by likedViewModel.likesUiState.collectAsState() // Trigger network call once when screen loads LaunchedEffect(Unit) { - likedViewModel.likedResponse(context) + likedViewModel.likedResponse(context,type) } Scaffold( @@ -95,7 +96,7 @@ class LikeANdMatchActivity : ComponentActivity() { color = MaterialTheme.colorScheme.error, fontWeight = FontWeight.Medium ) - Button(onClick = { likedViewModel.likedResponse(context) }) { + Button(onClick = { likedViewModel.likedResponse(context,"like") }) { Text("Retry") } } @@ -120,7 +121,6 @@ fun ProfileCard(context: Context, likedProfile: LikedUserResponse, modifier: Mod modifier = modifier.fillMaxWidth() ) { Column( - modifier = Modifier.padding(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { Box( @@ -128,6 +128,14 @@ fun ProfileCard(context: Context, likedProfile: LikedUserResponse, modifier: Mod .fillMaxWidth() .height(180.dp) .clip(RoundedCornerShape(12.dp)) + .clickable { +// Create an intent to launch your target activity (e.g., FriendProfileActivity) + val intent = Intent(context, FriendProfile::class.java).apply { + putExtra("USER_ID", likedProfile.id) // Pass the user ID here + } + context.startActivity(intent) + + onNameClick() } ) { // Use profile_image_url or fallback to the first media item AsyncImage( @@ -182,17 +190,10 @@ fun ProfileCard(context: Context, likedProfile: LikedUserResponse, modifier: Mod Column( modifier = Modifier .align(Alignment.BottomStart) - .clickable { -// Create an intent to launch your target activity (e.g., FriendProfileActivity) - val intent = Intent(context, FriendProfile::class.java).apply { - putExtra("USER_ID", likedProfile.id) // Pass the user ID here - } - context.startActivity(intent) - - onNameClick() } // Makes just this text section clickable + // Makes just this text section clickable .padding(8.dp) ){ - val displayName = likedProfile.full_name.ifBlank { "User" } + val displayName = likedProfile.full_name?.ifBlank { "User" } val age = remember(likedProfile.birth_date) { calculateAge(likedProfile.birth_date) } @@ -201,7 +202,7 @@ fun ProfileCard(context: Context, likedProfile: LikedUserResponse, modifier: Mod Log.d("user","$likedProfile.id") Text( - text = nameAndAge, + text = nameAndAge?:"", color = Color.White, fontWeight = FontWeight.Bold, fontSize = 14.sp diff --git a/app/src/main/java/com/example/dattingapp/Login/LoginActivity.kt b/app/src/main/java/com/example/dattingapp/Login/LoginActivity.kt index 464da43..e90d71f 100644 --- a/app/src/main/java/com/example/dattingapp/Login/LoginActivity.kt +++ b/app/src/main/java/com/example/dattingapp/Login/LoginActivity.kt @@ -270,13 +270,14 @@ fun LoginScreenContent( // Save retrieved tokens via TokenManager val tokenManager = TokenManager.getInstance(context) - val id=loginData.user?.profile?.full_name + val id=loginData.user?.id Log.d("useridlogin","$id") tokenManager.saveTokens( accessToken = loginData.accessToken ?: "", refreshToken = loginData.refreshToken ?: "", userId = loginData.user?.id ?: -1, - currenUserName = loginData.user?.profile?.full_name + currenUserName = loginData.user?.profile?.full_name, + profile_image_url=loginData.user?.profile?.profile_image_url ) Toast.makeText(context, "Login successful!", Toast.LENGTH_SHORT).show() diff --git a/app/src/main/java/com/example/dattingapp/ShowPostingActivity.kt b/app/src/main/java/com/example/dattingapp/ShowPostingActivity.kt index 19826ad..9758cf9 100644 --- a/app/src/main/java/com/example/dattingapp/ShowPostingActivity.kt +++ b/app/src/main/java/com/example/dattingapp/ShowPostingActivity.kt @@ -1,4 +1,5 @@ package com.example.dattingapp +import android.content.Intent import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent @@ -44,6 +45,7 @@ import com.example.dattingapp.homes.networkandapi.ShowPostUiState import com.example.dattingapp.homes.networkandapi.ShowPostViewModel import androidx.compose.material.icons.filled.Send import androidx.compose.material3.CardDefaults +import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview @@ -135,37 +137,51 @@ fun PostCard( .padding(horizontal = 12.dp, vertical = 8.dp), verticalAlignment = Alignment.CenterVertically ) { - Box( + AsyncImage( + model = post.author?.profile_image_url, + contentDescription = "Post author image", + placeholder = painterResource(id = R.drawable.locationpermissionbg), // your existing placeholder + error = painterResource(id = R.drawable.locationpermissionbg), modifier = Modifier .size(40.dp) - .clip(CircleShape) - .background(Color.LightGray), - contentAlignment = Alignment.Center - ) { - Text(text = post.author?.full_name?.take(1) ?: "U") - } + .clip(CircleShape), + contentScale = ContentScale.Crop + ) + Spacer(modifier = Modifier.width(8.dp)) Column { Row(verticalAlignment = Alignment.CenterVertically) { val authorName = post.author?.full_name ?: "Anonymous" val feelingText = post.feeling ?: "" + val context = LocalContext.current + // ✅ Clickable author name Text( - text = buildAnnotatedString { - withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) { - append("$authorName ") + text = authorName, + fontSize = 16.sp, + fontWeight = FontWeight.Bold, + modifier = Modifier.clickable { + val intent = Intent(context, FriendProfile::class.java).apply { + putExtra("USER_ID", post.author?.id) // ← send the user id } - if (feelingText.isNotEmpty()) { + context.startActivity(intent) + } + ) + + // Rest of the line, unchanged + if (feelingText.isNotEmpty()) { + Text( + text = buildAnnotatedString { withStyle(style = SpanStyle(fontWeight = FontWeight.Normal)) { append(" — feeling ") } withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) { append(feelingText) } - } - }, - fontSize = 16.sp - ) + }, + fontSize = 16.sp + ) + } } if (!post.location?.name.isNullOrEmpty()) { @@ -295,6 +311,7 @@ fun CommentSection( val tokenManager = remember { TokenManager.getInstance(context) } val currentUserName = remember { tokenManager.currentUserName() } + val currentProfileImage = remember { tokenManager.currentProfileImage() } // ✅ get the logged-in user's id once val currentUserId = remember { tokenManager.getUserId() } @@ -383,19 +400,16 @@ fun CommentSection( .padding(vertical = 6.dp), verticalAlignment = Alignment.CenterVertically ) { - Box( + AsyncImage( + model = currentProfileImage, + contentDescription = "Post author image", + placeholder = painterResource(id = R.drawable.locationpermissionbg), // your existing placeholder + error = painterResource(id = R.drawable.locationpermissionbg), modifier = Modifier .size(32.dp) - .clip(CircleShape) - .background(Color.LightGray), - contentAlignment = Alignment.Center - ) { - Text( - text = comment.author?.full_name?.take(1) ?: "U", - style = MaterialTheme.typography.bodySmall, - fontWeight = FontWeight.Bold - ) - } + .clip(CircleShape), + contentScale = ContentScale.Crop + ) Spacer(modifier = Modifier.width(8.dp)) @@ -513,6 +527,7 @@ fun ShowPostScreenPreview() { full_name = "Alex Rivera", city = "Shanghai", country = "China", + profile_image_url=null, compatibilityPercentage = 95 ), like_count = 12, @@ -542,6 +557,7 @@ fun ShowPostScreenPreview() { full_name = "Sarah", city = "Shanghai", country = "China", + profile_image_url=null, compatibilityPercentage = 100 ), createdAt = "2026-10-13T07:45:15" @@ -555,6 +571,7 @@ fun ShowPostScreenPreview() { full_name = "David", city = "Beijing", country = "China", + profile_image_url=null, compatibilityPercentage = 90 ), createdAt = "2026-10-13T08:04:48" diff --git a/app/src/main/java/com/example/dattingapp/dataclass/DataClass.kt b/app/src/main/java/com/example/dattingapp/dataclass/DataClass.kt index d2a6174..18fda77 100644 --- a/app/src/main/java/com/example/dattingapp/dataclass/DataClass.kt +++ b/app/src/main/java/com/example/dattingapp/dataclass/DataClass.kt @@ -32,6 +32,10 @@ data class Author( val full_name: String?, val city: String?, val country: String?, + + @SerialName("profile_image_url") + val profile_image_url:String?, + @SerialName("compatibility_percentage") val compatibilityPercentage: Int? = 0 ) diff --git a/app/src/main/java/com/example/dattingapp/homes/ExploreScreen.kt b/app/src/main/java/com/example/dattingapp/homes/ExploreScreen.kt index 98492e5..a4591ee 100644 --- a/app/src/main/java/com/example/dattingapp/homes/ExploreScreen.kt +++ b/app/src/main/java/com/example/dattingapp/homes/ExploreScreen.kt @@ -54,6 +54,7 @@ import com.example.dattingapp.ui.theme.OverlayShadow import com.example.dattingapp.ui.theme.TextPostTextColor import com.example.dattingapp.ui.theme.lightChipBg import com.example.dattingapp.ui.theme.primaryColor +import kotlinx.serialization.SerialName // Data Models @@ -628,6 +629,7 @@ private val mockFeed = listOf( full_name = "Alex Rivera", city = "Shanghai", country = "China", + profile_image_url = null, compatibilityPercentage = 95 ), like_count = 12, @@ -657,6 +659,7 @@ private val mockFeed = listOf( full_name = "Sarah", city = "Beijing", country = "China", + profile_image_url = null, compatibilityPercentage = 88 ), like_count = 0, diff --git a/app/src/main/java/com/example/dattingapp/homes/MeetScreen.kt b/app/src/main/java/com/example/dattingapp/homes/MeetScreen.kt index 83c4c21..91aaae1 100644 --- a/app/src/main/java/com/example/dattingapp/homes/MeetScreen.kt +++ b/app/src/main/java/com/example/dattingapp/homes/MeetScreen.kt @@ -4,6 +4,7 @@ import android.content.Context import android.content.Intent import android.util.Log import androidx.compose.animation.core.Animatable +import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* @@ -205,27 +206,38 @@ private fun ProfileCardItem( } val defaultPainter = rememberVectorPainter(Icons.Default.Person) - AsyncImage( - model = ImageRequest.Builder(context) - .data(photoUrl.takeIf { !it.isNullOrBlank() }) - .apply { - if (!token.isNullOrBlank()) { - val authHeader = if (token.startsWith("Bearer ", ignoreCase = true)) token else "Bearer $token" - addHeader("Authorization", authHeader) + if (!photoUrl.isNullOrBlank()) { + AsyncImage( + model = ImageRequest.Builder(context) + .data(photoUrl) // ← guaranteed non-null here + .apply { + if (!token.isNullOrBlank()) { + val authHeader = + if (token.startsWith("Bearer ", ignoreCase = true)) token + else "Bearer $token" + addHeader("Authorization", authHeader) + } } + .crossfade(true) + .build(), + placeholder = defaultPainter, + error = defaultPainter, + contentDescription = "Profile Image", + modifier = Modifier.fillMaxSize(), + contentScale = ContentScale.Crop, + onError = { errorState -> + Log.e("CoilStatus", "Failed to load image", errorState.result.throwable) } - .crossfade(true) - .build(), - placeholder = defaultPainter, - error = defaultPainter, - fallback = defaultPainter, // Shows Icons.Default.Person immediately when photoUrl is null/blank - contentDescription = "Profile Image", - modifier = Modifier.fillMaxSize(), - contentScale = ContentScale.Crop, - onError = { errorState -> - Log.e("CoilStatus", "Failed to load image", errorState.result.throwable) - } - ) + ) + } else { + // No URL at all → show the default directly, Coil never runs + Image( + painter = defaultPainter, + contentDescription = "Profile Image", + modifier = Modifier.fillMaxSize(), + contentScale = ContentScale.Crop + ) + } // DARK GRADIENT OVERLAY Box( diff --git a/app/src/main/java/com/example/dattingapp/homes/MyProfile.kt b/app/src/main/java/com/example/dattingapp/homes/MyProfile.kt index abe6893..886dac7 100644 --- a/app/src/main/java/com/example/dattingapp/homes/MyProfile.kt +++ b/app/src/main/java/com/example/dattingapp/homes/MyProfile.kt @@ -45,6 +45,7 @@ import androidx.core.content.ContextCompat.startActivity // MY PROFILE SCREEN // ============================================================ + @Composable fun MyProfileScreen( profileResponse : UserResponse?, // Change from MyProfileData? to MyProfileResponse? @@ -305,7 +306,10 @@ fun MyProfileScreen( label = "Likes", modifier = Modifier.weight(1f), onClick = { - val intent = Intent(context, LikeANdMatchActivity::class.java) + val intent = Intent(context, LikeANdMatchActivity::class.java).apply { + putExtra("TYPE", "Likes") // ← e.g. "like", "liked", or "matches" + // putExtra("USER_ID", userId.toString()) // ← if you also need a user id + } context.startActivity(intent) onLikesClick() } @@ -316,7 +320,14 @@ fun MyProfileScreen( number = profileResponse?.liked_by_users_count?.toString() ?: "0", label = "Liked", modifier = Modifier.weight(1f), - onClick = { /* Optional: Handle Matches click */ } + onClick = { + val intent = Intent(context, LikeANdMatchActivity::class.java).apply { + putExtra("TYPE", "Liked") // ← e.g. "like", "liked", or "matches" + // putExtra("USER_ID", userId.toString()) // ← if you also need a user id + } + context.startActivity(intent) + onLikesClick() + } ) @@ -330,7 +341,14 @@ fun MyProfileScreen( number = profileResponse?.matches_count?.toString() ?: "0", label = "Matches", modifier = Modifier.weight(1f), - onClick = { /* Optional: Handle Matches click */ } + onClick = { + val intent = Intent(context, LikeANdMatchActivity::class.java).apply { + putExtra("TYPE", "Matches") // ← e.g. "like", "liked", or "matches" + // putExtra("USER_ID", userId.toString()) // ← if you also need a user id + } + context.startActivity(intent) + onLikesClick() + } ) } Spacer( @@ -346,6 +364,8 @@ fun MyProfileScreen( } + + // ============================================================ // PROFILE MEDIA GRID // ============================================================ @@ -414,7 +434,7 @@ private fun StatCard( ) { Column( - modifier = Modifier.fillMaxWidth().padding(vertical = 12.dp), + modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), horizontalAlignment = Alignment.CenterHorizontally ) { Text( diff --git a/app/src/main/java/com/example/dattingapp/homes/networkandapi/HomeApiService.kt b/app/src/main/java/com/example/dattingapp/homes/networkandapi/HomeApiService.kt index 15a788e..ada4044 100644 --- a/app/src/main/java/com/example/dattingapp/homes/networkandapi/HomeApiService.kt +++ b/app/src/main/java/com/example/dattingapp/homes/networkandapi/HomeApiService.kt @@ -69,9 +69,20 @@ interface HomeApiService { ): Response @GET("api/v1/users/me/liked") + suspend fun getLikeUsers( + ): Response> + + @GET("/api/v1/users/me/likes") suspend fun getLikedUsers( ): Response> + @GET("/api/v1/matches") + suspend fun getMatches( + @Query("limit") limit: Int = 20, + @Query("offset") offset: Int = 0 + ): Response> + + @GET("api/v1/explore/posts/{post_id}") suspend fun getPostById( @Path("post_id") postId: Int diff --git a/app/src/main/java/com/example/dattingapp/homes/networkandapi/HomeViewModelClass.kt b/app/src/main/java/com/example/dattingapp/homes/networkandapi/HomeViewModelClass.kt index 2882052..7aaa277 100644 --- a/app/src/main/java/com/example/dattingapp/homes/networkandapi/HomeViewModelClass.kt +++ b/app/src/main/java/com/example/dattingapp/homes/networkandapi/HomeViewModelClass.kt @@ -534,49 +534,62 @@ sealed interface LikedUiState { class LikedViewModel : ViewModel() { - private val _likeUiState = MutableStateFlow(LikedUiState.Idle) - val likeUiState: StateFlow = _likeUiState.asStateFlow() + // ✅ three separate states, one per list type + private val _likesUiState = MutableStateFlow(LikedUiState.Idle) // users who liked ME + val likesUiState: StateFlow = _likesUiState.asStateFlow() - fun likedResponse(context: Context) { - if (_likeUiState.value is LikedUiState.Loading) return + private val _likedUiState = MutableStateFlow(LikedUiState.Idle) // users I liked + val likedUiState: StateFlow = _likedUiState.asStateFlow() + private val _matchesUiState = MutableStateFlow(LikedUiState.Idle) // matches + val matchesUiState: StateFlow = _matchesUiState.asStateFlow() + + fun likedResponse(context: Context, type: String) { val appContext = context.applicationContext + // ✅ pick which state this call writes to + val targetFlow = when (type) { + "Likes" -> _likesUiState + "Liked" -> _likedUiState + else -> _matchesUiState + } + + if (targetFlow.value is LikedUiState.Loading) return + viewModelScope.launch { - _likeUiState.value = LikedUiState.Loading + targetFlow.value = LikedUiState.Loading if (TokenManager.getInstance(appContext).getAccessToken().isNullOrBlank()) { Log.e("MeetApi", "No access token in user_tokens preferences") - _likeUiState.value = LikedUiState.Error("No access token found. Please log in again.") + targetFlow.value = LikedUiState.Error("No access token found. Please log in again.") return@launch } try { - // Returns CreatePostResponse directly - val createdPost = HomeNetworkModule - .getApiService(appContext) - .getLikedUsers() + val createdPost = when (type) { + "Likes" -> HomeNetworkModule.getApiService(appContext).getLikeUsers() + "Liked" -> HomeNetworkModule.getApiService(appContext).getLikedUsers() + else -> HomeNetworkModule.getApiService(appContext).getMatches(20, 10) + } - Log.d("CreatePostDebug", "Response Code: ${createdPost.code()}") + Log.d("CreatePostDebug", "$type Response Code: ${createdPost.code()}") if (createdPost.isSuccessful && createdPost.body() != null) { - _likeUiState.value = LikedUiState.Success(createdPost.body()!!) // Use .body() here! - + targetFlow.value = LikedUiState.Success(createdPost.body()!!) } else { - _likeUiState.value = LikedUiState.Error("No post data received from the server.") + targetFlow.value = LikedUiState.Error("No data received from the server.") } } catch (e: HttpException) { - // Handle HTTP errors via HttpException automatically thrown by Retrofit val message = when (e.code()) { 401 -> "Authentication failed. Please log in again." 403 -> "The server refused access to this profile." 404 -> "User profile was not found." else -> "Request failed: HTTP ${e.code()}." } - _likeUiState.value = LikedUiState.Error(message) + targetFlow.value = LikedUiState.Error(message) } catch (e: Exception) { Log.e("MeetApi", "Unexpected request failure", e) - _likeUiState.value = LikedUiState.Error("Request failed: ${e.javaClass.simpleName}") + targetFlow.value = LikedUiState.Error("Request failed: ${e.javaClass.simpleName}") } } } @@ -653,6 +666,7 @@ class ShowPostViewModel : ViewModel() { full_name = currentUserName ?: "You", city = null, country = null, + profile_image_url = null, compatibilityPercentage = null ), createdAt = "Just now" diff --git a/app/src/main/java/com/example/dattingapp/homes/networkandapi/TokenManager.kt b/app/src/main/java/com/example/dattingapp/homes/networkandapi/TokenManager.kt index ee36cc5..e406cb3 100644 --- a/app/src/main/java/com/example/dattingapp/homes/networkandapi/TokenManager.kt +++ b/app/src/main/java/com/example/dattingapp/homes/networkandapi/TokenManager.kt @@ -11,7 +11,7 @@ class TokenManager private constructor(context: Context) { Context.MODE_PRIVATE ) - fun saveTokens(accessToken: String, refreshToken: String?,userId: Int,currenUserName:String?) { + fun saveTokens(accessToken: String, refreshToken: String?,userId: Int,currenUserName:String?,profile_image_url:String?) { val cleanToken = accessToken.trim() .replace( Regex("^Bearer\\s+", RegexOption.IGNORE_CASE), @@ -24,6 +24,7 @@ class TokenManager private constructor(context: Context) { .putString(KEY_REFRESH_TOKEN, refreshToken) .putInt("user_id", userId) .putString("currenUserName", currenUserName) + .putString("profile_image_url", profile_image_url) .commit() // Do not log the token itself. @@ -37,6 +38,7 @@ class TokenManager private constructor(context: Context) { } fun currentUserName(): String? = preferences.getString("full_name", null) + fun currentProfileImage(): String? = preferences.getString("profile_image_url", null) fun getAccessToken(): String? { return preferences.getString(KEY_ACCESS_TOKEN, null) diff --git a/app/src/main/java/com/example/dattingapp/registration/RegisterRequest.kt b/app/src/main/java/com/example/dattingapp/registration/RegisterRequest.kt index ae6ebb5..b138364 100644 --- a/app/src/main/java/com/example/dattingapp/registration/RegisterRequest.kt +++ b/app/src/main/java/com/example/dattingapp/registration/RegisterRequest.kt @@ -74,5 +74,7 @@ data class LoginUser( data class LoginProfile( @SerializedName("full_name") - val full_name: String? = null + val full_name: String? = null, + @SerializedName("profile_image_url") + val profile_image_url: String? = null ) diff --git a/app/src/main/java/com/example/dattingapp/ui/theme/Color.kt b/app/src/main/java/com/example/dattingapp/ui/theme/Color.kt index 785ea8b..804ab6d 100644 --- a/app/src/main/java/com/example/dattingapp/ui/theme/Color.kt +++ b/app/src/main/java/com/example/dattingapp/ui/theme/Color.kt @@ -113,7 +113,7 @@ colors = listOf( Color(0xFF6B00B0) // Deep Purple ) ) -val purpleButtonColor = Color(0xFF6B00F5) +val purpleButtonColor = Color(0x236B00F5) // Same post id always gives the same color val OverlayShadow = Shadow(