Compare commits

...

2 Commits

Author SHA1 Message Date
osman160128 58b14651e8 feed 2 weeks ago
osman160128 fbd1f81c9a friend profile update 2 weeks ago
  1. 187
      app/src/main/java/com/example/dattingapp/FriendProfile.kt
  2. 68
      app/src/main/java/com/example/dattingapp/LikeANdMatchActivity.kt
  3. 13
      app/src/main/java/com/example/dattingapp/Login/LoginActivity.kt
  4. 69
      app/src/main/java/com/example/dattingapp/ShowPostingActivity.kt
  5. 4
      app/src/main/java/com/example/dattingapp/dataclass/DataClass.kt
  6. 116
      app/src/main/java/com/example/dattingapp/homes/ExploreScreen.kt
  7. 50
      app/src/main/java/com/example/dattingapp/homes/MeetScreen.kt
  8. 686
      app/src/main/java/com/example/dattingapp/homes/MyProfile.kt
  9. 11
      app/src/main/java/com/example/dattingapp/homes/networkandapi/HomeApiService.kt
  10. 48
      app/src/main/java/com/example/dattingapp/homes/networkandapi/HomeViewModelClass.kt
  11. 23
      app/src/main/java/com/example/dattingapp/homes/networkandapi/TokenManager.kt
  12. 4
      app/src/main/java/com/example/dattingapp/registration/RegisterRequest.kt
  13. 8
      app/src/main/java/com/example/dattingapp/registration/RegistrationScreen.kt
  14. 2
      app/src/main/java/com/example/dattingapp/ui/theme/Color.kt

187
app/src/main/java/com/example/dattingapp/FriendProfile.kt

@ -31,6 +31,7 @@ import androidx.compose.material.icons.filled.TextSnippet
import androidx.compose.material.icons.outlined.LocationOn import androidx.compose.material.icons.outlined.LocationOn
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
@ -51,6 +52,7 @@ import com.example.dattingapp.homes.profile.FrienPostMedia
import com.example.dattingapp.homes.profile.FriendAuthor import com.example.dattingapp.homes.profile.FriendAuthor
import com.example.dattingapp.homes.profile.FriendPost import com.example.dattingapp.homes.profile.FriendPost
import com.example.dattingapp.homes.profile.FriendProfileResponse import com.example.dattingapp.homes.profile.FriendProfileResponse
import com.example.dattingapp.homes.profile.LikedUserResponse
import com.example.dattingapp.ui.theme.* import com.example.dattingapp.ui.theme.*
import java.time.LocalDate import java.time.LocalDate
import java.time.Period import java.time.Period
@ -82,6 +84,9 @@ class FriendProfile : ComponentActivity() {
} }
} }
when (val state = profileUiState) { when (val state = profileUiState) {
is FriendProfileUiState.Loading -> { is FriendProfileUiState.Loading -> {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
@ -120,6 +125,42 @@ fun FriendProfileScreen(
onStarClick: () -> Unit = {}, onStarClick: () -> Unit = {},
onCancelClick: () -> 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 iLikedIds = (likesState as? LikedUiState.Success)
?.LikeData?.map { it.id }?.toSet() ?: emptySet()
val likedMeIds = (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
// ✅ add this at the top of FriendProfileScreen, next to your other states
var localLiked by rememberSaveable { mutableStateOf(false) }
// Like is disabled if: I liked them before (server) OR I just clicked Like now
val likeDisabled = iLikedHim || localLiked
val age = remember(friendProfileData.birth_date) { val age = remember(friendProfileData.birth_date) {
calculateAge(friendProfileData.birth_date) calculateAge(friendProfileData.birth_date)
} }
@ -269,7 +310,7 @@ fun FriendProfileScreen(
) )
} }
// Action Buttons Row //action button
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -277,86 +318,124 @@ fun FriendProfileScreen(
horizontalArrangement = Arrangement.spacedBy(10.dp), horizontalArrangement = Arrangement.spacedBy(10.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Button( // Message — card style, no background color
// Message — enabled only when matched, grayed out otherwise
Card(
onClick = onMessageClick, onClick = onMessageClick,
enabled = isMatch, // ✅ disabled when not matched
modifier = Modifier modifier = Modifier
.weight(1f) .weight(1f)
.height(48.dp) .height(48.dp),
.background( shape = RoundedCornerShape(10.dp),
brush = gradientBrush, colors = CardDefaults.cardColors(
shape = RoundedCornerShape(10.dp) containerColor = if (isMatch) Color.White else Color(0xFFF0F0F0),
), disabledContainerColor = Color(0xFFF0F0F0)
colors = ButtonDefaults.buttonColors(
containerColor = Color.Transparent,
contentColor = Color.White
), ),
shape = RoundedCornerShape(10.dp) elevation = CardDefaults.cardElevation(
) { defaultElevation = if (isMatch) 4.dp else 0.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
) )
) {
Row(
modifier = Modifier.fillMaxSize(),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = Icons.Default.ChatBubble,
contentDescription = "Message",
tint = if (isMatch) textDark else Color(0xFFBDBDBD), // gray when disabled
modifier = Modifier.size(18.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = "Message",
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
color = if (isMatch) textDark else Color(0xFFBDBDBD) // gray when disabled
)
}
} }
IconButton(
// ❤️ Like — red ICON when the user liked ME, normal otherwise
// hidden when matched
// ❤️ Like — RED background if user liked me, DISABLED if I liked them
Card(
onClick = { onClick = {
onLikeClick() onLikeClick()
handleLikeAndDislikeAction(context, "right", friendProfileData, swipeViewModel) handleLikeAndDislikeAction(context, "right", friendProfileData, swipeViewModel)
localLiked = true // ✅ disable after first click
}, },
modifier = Modifier enabled = !likeDisabled,
.size(48.dp) modifier = Modifier.size(48.dp),
.background(color = purpleButtonColor, shape = RoundedCornerShape(10.dp)) shape = RoundedCornerShape(10.dp),
) { colors = CardDefaults.cardColors(
Icon( containerColor = if (heLikedMe) Color(0xFFE53935) else Color.White,
imageVector = Icons.Default.Favorite, disabledContainerColor = if (heLikedMe) Color(0xFFE53935) else Color(0xFFF0F0F0)
contentDescription = "Like", ),
tint = Color(0xFFE2C4FF), elevation = CardDefaults.cardElevation(
modifier = Modifier.size(20.dp) defaultElevation = if (likeDisabled) 0.dp else 2.dp
) )
) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Icon(
imageVector = Icons.Default.Favorite,
contentDescription = "Like",
tint = when {
heLikedMe -> Color.White // white heart on red background
likeDisabled -> Color(0xFFBDBDBD) // gray when disabled
else -> textDark // normal
},
modifier = Modifier.size(20.dp)
)
}
} }
IconButton( // Super Like — card style
Card(
onClick = { onClick = {
onStarClick() onStarClick()
handleLikeAndDislikeAction(context, "right", friendProfileData, swipeViewModel) handleLikeAndDislikeAction(context, "right", friendProfileData, swipeViewModel)
}, },
modifier = Modifier modifier = Modifier.size(48.dp),
.size(48.dp) shape = RoundedCornerShape(10.dp),
.background(color = purpleButtonColor, shape = RoundedCornerShape(10.dp)) colors = CardDefaults.cardColors(containerColor = Color.White),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
) { ) {
Icon( Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
imageVector = Icons.Default.Star, Icon(
contentDescription = "Favorite", imageVector = Icons.Default.Star,
tint = Color(0xFFE2C4FF), contentDescription = "Favorite",
modifier = Modifier.size(20.dp) tint = textDark,
) modifier = Modifier.size(20.dp)
} )
}
}
IconButton( // Cancel — card style, always visible
// Cancel — clicking it re-enables the Like button
Card(
onClick = { onClick = {
onCancelClick() onCancelClick()
handleLikeAndDislikeAction(context, "left", friendProfileData, swipeViewModel) handleLikeAndDislikeAction(context, "left", friendProfileData, swipeViewModel)
localLiked = false // ✅ Like button works again
}, },
modifier = Modifier modifier = Modifier.size(48.dp),
.size(48.dp) shape = RoundedCornerShape(10.dp),
.background(color = purpleButtonColor, shape = RoundedCornerShape(10.dp)) colors = CardDefaults.cardColors(containerColor = Color.White),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
) { ) {
Icon( Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
imageVector = Icons.Default.Close, Icon(
contentDescription = "Dislike", imageVector = Icons.Default.Close,
tint = Color(0xFFE2C4FF), contentDescription = "Dislike",
modifier = Modifier.size(20.dp) tint = textDark,
) modifier = Modifier.size(20.dp)
)
}
} }
} }
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
// User Posts Grid Section below Action Row // User Posts Grid Section below Action Row

68
app/src/main/java/com/example/dattingapp/LikeANdMatchActivity.kt

@ -15,6 +15,8 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Favorite import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.LocationOn import androidx.compose.material.icons.filled.LocationOn
import androidx.compose.material3.* import androidx.compose.material3.*
@ -54,17 +56,50 @@ class LikeANdMatchActivity : ComponentActivity() {
DattingAPPTheme { DattingAPPTheme {
val likedViewModel: LikedViewModel = viewModel() val likedViewModel: LikedViewModel = viewModel()
val context = LocalContext.current val context = LocalContext.current
val type = intent.getStringExtra("TYPE") ?: "Likes"
// Collect state from ViewModel // Dynamically collect the correct StateFlow based on the 'type'
val uiState by likedViewModel.likeUiState.collectAsState() val uiState by when (type) {
"Likes" -> likedViewModel.likesUiState.collectAsState()
"Liked" -> likedViewModel.likedUiState.collectAsState()
else -> likedViewModel.matchesUiState.collectAsState()
}
// Trigger network call once when screen loads // Trigger network call once when screen loads
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
likedViewModel.likedResponse(context) likedViewModel.likedResponse(context, type)
} }
Scaffold( Scaffold(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
topBar = {
@OptIn(ExperimentalMaterial3Api::class)
TopAppBar(
title = {
// Display dynamic title based on the page type
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 -> ) { innerPadding ->
Box( Box(
modifier = Modifier modifier = Modifier
@ -78,7 +113,7 @@ class LikeANdMatchActivity : ComponentActivity() {
} }
is LikedUiState.Success -> { is LikedUiState.Success -> {
ProfileGrid( ProfileGrid(
context =context, context = context,
likedResponse = state.LikeData, likedResponse = state.LikeData,
isLoading = false, isLoading = false,
errorMessage = null errorMessage = null
@ -95,7 +130,7 @@ class LikeANdMatchActivity : ComponentActivity() {
color = MaterialTheme.colorScheme.error, color = MaterialTheme.colorScheme.error,
fontWeight = FontWeight.Medium fontWeight = FontWeight.Medium
) )
Button(onClick = { likedViewModel.likedResponse(context) }) { Button(onClick = { likedViewModel.likedResponse(context, type) }) {
Text("Retry") Text("Retry")
} }
} }
@ -107,7 +142,6 @@ class LikeANdMatchActivity : ComponentActivity() {
} }
} }
} }
// 1. Define ProfileCard FIRST so ProfileGrid can reference it without issue // 1. Define ProfileCard FIRST so ProfileGrid can reference it without issue
@Composable @Composable
fun ProfileCard(context: Context, likedProfile: LikedUserResponse, modifier: Modifier = Modifier, fun ProfileCard(context: Context, likedProfile: LikedUserResponse, modifier: Modifier = Modifier,
@ -120,7 +154,6 @@ fun ProfileCard(context: Context, likedProfile: LikedUserResponse, modifier: Mod
modifier = modifier.fillMaxWidth() modifier = modifier.fillMaxWidth()
) { ) {
Column( Column(
modifier = Modifier.padding(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp) verticalArrangement = Arrangement.spacedBy(8.dp)
) { ) {
Box( Box(
@ -128,6 +161,14 @@ fun ProfileCard(context: Context, likedProfile: LikedUserResponse, modifier: Mod
.fillMaxWidth() .fillMaxWidth()
.height(180.dp) .height(180.dp)
.clip(RoundedCornerShape(12.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 // Use profile_image_url or fallback to the first media item
AsyncImage( AsyncImage(
@ -182,17 +223,10 @@ fun ProfileCard(context: Context, likedProfile: LikedUserResponse, modifier: Mod
Column( Column(
modifier = Modifier modifier = Modifier
.align(Alignment.BottomStart) .align(Alignment.BottomStart)
.clickable { // Makes just this text section 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
.padding(8.dp) .padding(8.dp)
){ ){
val displayName = likedProfile.full_name.ifBlank { "User" } val displayName = likedProfile.full_name?.ifBlank { "User" }
val age = remember(likedProfile.birth_date) { val age = remember(likedProfile.birth_date) {
calculateAge(likedProfile.birth_date) calculateAge(likedProfile.birth_date)
} }
@ -201,7 +235,7 @@ fun ProfileCard(context: Context, likedProfile: LikedUserResponse, modifier: Mod
Log.d("user","$likedProfile.id") Log.d("user","$likedProfile.id")
Text( Text(
text = nameAndAge, text = nameAndAge?:"",
color = Color.White, color = Color.White,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
fontSize = 14.sp fontSize = 14.sp

13
app/src/main/java/com/example/dattingapp/Login/LoginActivity.kt

@ -270,15 +270,20 @@ fun LoginScreenContent(
// Save retrieved tokens via TokenManager // Save retrieved tokens via TokenManager
val tokenManager = TokenManager.getInstance(context) val tokenManager = TokenManager.getInstance(context)
val id=loginData.user?.profile?.full_name val id=loginData.user?.id
Log.d("useridlogin","$id") Log.d("useridlogin","$id")
tokenManager.saveTokens( tokenManager.saveTokens(
accessToken = loginData.accessToken ?: "", accessToken = loginData.accessToken ?: "",
refreshToken = loginData.refreshToken ?: "", refreshToken = loginData.refreshToken ?: ""
userId = loginData.user?.id ?: -1,
currenUserName = loginData.user?.profile?.full_name
) )
tokenManager.saveProfile(
userId = loginData.user?.id ?: -1,
currenUserName = loginData.user?.profile?.full_name,
profile_image_url=loginData.user?.profile?.profile_image_url
)
Toast.makeText(context, "Login successful!", Toast.LENGTH_SHORT).show() Toast.makeText(context, "Login successful!", Toast.LENGTH_SHORT).show()
onLoginSuccess() onLoginSuccess()
} else { } else {

69
app/src/main/java/com/example/dattingapp/ShowPostingActivity.kt

@ -1,4 +1,5 @@
package com.example.dattingapp package com.example.dattingapp
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
@ -44,6 +45,7 @@ import com.example.dattingapp.homes.networkandapi.ShowPostUiState
import com.example.dattingapp.homes.networkandapi.ShowPostViewModel import com.example.dattingapp.homes.networkandapi.ShowPostViewModel
import androidx.compose.material.icons.filled.Send import androidx.compose.material.icons.filled.Send
import androidx.compose.material3.CardDefaults import androidx.compose.material3.CardDefaults
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
@ -135,37 +137,51 @@ fun PostCard(
.padding(horizontal = 12.dp, vertical = 8.dp), .padding(horizontal = 12.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically 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 modifier = Modifier
.size(40.dp) .size(40.dp)
.clip(CircleShape) .clip(CircleShape),
.background(Color.LightGray), contentScale = ContentScale.Crop
contentAlignment = Alignment.Center )
) {
Text(text = post.author?.full_name?.take(1) ?: "U")
}
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
Column { Column {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
val authorName = post.author?.full_name ?: "Anonymous" val authorName = post.author?.full_name ?: "Anonymous"
val feelingText = post.feeling ?: "" val feelingText = post.feeling ?: ""
val context = LocalContext.current
// ✅ Clickable author name
Text( Text(
text = buildAnnotatedString { text = authorName,
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) { fontSize = 16.sp,
append("$authorName ") 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)) { withStyle(style = SpanStyle(fontWeight = FontWeight.Normal)) {
append(" — feeling ") append(" — feeling ")
} }
withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) { withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
append(feelingText) append(feelingText)
} }
} },
}, fontSize = 16.sp
fontSize = 16.sp )
) }
} }
if (!post.location?.name.isNullOrEmpty()) { if (!post.location?.name.isNullOrEmpty()) {
@ -295,6 +311,7 @@ fun CommentSection(
val tokenManager = remember { TokenManager.getInstance(context) } val tokenManager = remember { TokenManager.getInstance(context) }
val currentUserName = remember { tokenManager.currentUserName() } val currentUserName = remember { tokenManager.currentUserName() }
val currentProfileImage = remember { tokenManager.currentProfileImage() }
// ✅ get the logged-in user's id once // ✅ get the logged-in user's id once
val currentUserId = remember { tokenManager.getUserId() } val currentUserId = remember { tokenManager.getUserId() }
@ -383,19 +400,16 @@ fun CommentSection(
.padding(vertical = 6.dp), .padding(vertical = 6.dp),
verticalAlignment = Alignment.CenterVertically 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 modifier = Modifier
.size(32.dp) .size(32.dp)
.clip(CircleShape) .clip(CircleShape),
.background(Color.LightGray), contentScale = ContentScale.Crop
contentAlignment = Alignment.Center )
) {
Text(
text = comment.author?.full_name?.take(1) ?: "U",
style = MaterialTheme.typography.bodySmall,
fontWeight = FontWeight.Bold
)
}
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
@ -513,6 +527,7 @@ fun ShowPostScreenPreview() {
full_name = "Alex Rivera", full_name = "Alex Rivera",
city = "Shanghai", city = "Shanghai",
country = "China", country = "China",
profile_image_url=null,
compatibilityPercentage = 95 compatibilityPercentage = 95
), ),
like_count = 12, like_count = 12,
@ -542,6 +557,7 @@ fun ShowPostScreenPreview() {
full_name = "Sarah", full_name = "Sarah",
city = "Shanghai", city = "Shanghai",
country = "China", country = "China",
profile_image_url=null,
compatibilityPercentage = 100 compatibilityPercentage = 100
), ),
createdAt = "2026-10-13T07:45:15" createdAt = "2026-10-13T07:45:15"
@ -555,6 +571,7 @@ fun ShowPostScreenPreview() {
full_name = "David", full_name = "David",
city = "Beijing", city = "Beijing",
country = "China", country = "China",
profile_image_url=null,
compatibilityPercentage = 90 compatibilityPercentage = 90
), ),
createdAt = "2026-10-13T08:04:48" createdAt = "2026-10-13T08:04:48"

4
app/src/main/java/com/example/dattingapp/dataclass/DataClass.kt

@ -32,6 +32,10 @@ data class Author(
val full_name: String?, val full_name: String?,
val city: String?, val city: String?,
val country: String?, val country: String?,
@SerialName("profile_image_url")
val profile_image_url:String?,
@SerialName("compatibility_percentage") val compatibilityPercentage: Int? = 0 @SerialName("compatibility_percentage") val compatibilityPercentage: Int? = 0
) )

116
app/src/main/java/com/example/dattingapp/homes/ExploreScreen.kt

@ -30,6 +30,7 @@ import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.graphics.luminance import androidx.compose.ui.graphics.luminance
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
@ -42,18 +43,21 @@ import androidx.media3.common.Player
import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.PlayerView import androidx.media3.ui.PlayerView
import coil.compose.AsyncImage import coil.compose.AsyncImage
import com.example.dattingapp.R
import com.example.dattingapp.ShowPostingActivity import com.example.dattingapp.ShowPostingActivity
import com.example.dattingapp.dataclass.Author import com.example.dattingapp.dataclass.Author
import com.example.dattingapp.dataclass.Location import com.example.dattingapp.dataclass.Location
import com.example.dattingapp.dataclass.MediaItem import com.example.dattingapp.dataclass.MediaItem
import com.example.dattingapp.dataclass.ShowPostResponse import com.example.dattingapp.dataclass.ShowPostResponse
import com.example.dattingapp.homes.networkandapi.PostResponse import com.example.dattingapp.homes.networkandapi.PostResponse
import com.example.dattingapp.homes.networkandapi.TokenManager
import com.example.dattingapp.homes.profile.UserResponse import com.example.dattingapp.homes.profile.UserResponse
import com.example.dattingapp.ui.theme.DattingAPPTheme import com.example.dattingapp.ui.theme.DattingAPPTheme
import com.example.dattingapp.ui.theme.OverlayShadow import com.example.dattingapp.ui.theme.OverlayShadow
import com.example.dattingapp.ui.theme.TextPostTextColor import com.example.dattingapp.ui.theme.TextPostTextColor
import com.example.dattingapp.ui.theme.lightChipBg import com.example.dattingapp.ui.theme.lightChipBg
import com.example.dattingapp.ui.theme.primaryColor import com.example.dattingapp.ui.theme.primaryColor
import kotlinx.serialization.SerialName
// Data Models // Data Models
@ -63,15 +67,6 @@ data class VibeCategory(
val isSelected: Boolean = false val isSelected: Boolean = false
) )
data class EventCardData(
val id: String,
val title: String,
val description: String,
val imageUrl: String,
val tagLabel: String,
val isTrending: Boolean = false,
val tags: List<String> = emptyList()
)
data class UserMatch( data class UserMatch(
val id: String, val id: String,
@ -131,6 +126,10 @@ fun VibeCheckHomeScreen(
private fun VibeCheckTopAppBar( private fun VibeCheckTopAppBar(
primaryColor: Color primaryColor: Color
) { ) {
val context = LocalContext.current
val tokenManager = remember { TokenManager.getInstance(context) }
val currentUserName = remember { tokenManager.currentUserName() }
val currentProfileImage = remember { tokenManager.currentProfileImage() }
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@ -146,17 +145,22 @@ private fun VibeCheckTopAppBar(
} }
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Box(
AsyncImage(
model = currentProfileImage,
contentDescription = "Post author image",
placeholder = painterResource(id = com.example.dattingapp.R.drawable.locationpermissionbg), // your existing placeholder
error = painterResource(id = R.drawable.locationpermissionbg),
modifier = Modifier modifier = Modifier
.size(32.dp) .size(40.dp)
.clip(CircleShape) .clip(CircleShape),
.background(Color.Gray) contentScale = ContentScale.Crop
) )
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(2.dp))
Text( Text(
text = "VibeCheck", text = currentUserName?:"",
color = primaryColor, color = primaryColor,
fontSize = 20.sp, fontSize = 20.sp,
fontWeight = FontWeight.Bold fontWeight = FontWeight.Bold
@ -176,47 +180,53 @@ private fun VibeCheckTopAppBar(
private fun SearchBarSection() { private fun SearchBarSection() {
var searchText by remember { mutableStateOf("") } var searchText by remember { mutableStateOf("") }
OutlinedTextField( OutlinedTextField(
value = searchText, value = searchText,
onValueChange = { searchText = it }, onValueChange = { searchText = it },
placeholder = { placeholder = {
Text(text = "Search", color = Color.Gray) Text(text = "Search", color = Color.Gray, fontSize = 13.sp)
}, },
leadingIcon = { leadingIcon = {
Icon(
imageVector = Icons.Default.Search,
contentDescription = null,
tint = Color.Gray
)
},
trailingIcon = {
Row(modifier = Modifier.padding(end = 8.dp)) {
Icon(
imageVector = Icons.Outlined.Image,
contentDescription = null,
tint = Color.Gray
)
Spacer(modifier = Modifier.width(8.dp))
Icon( Icon(
imageVector = Icons.Outlined.LocationOn, imageVector = Icons.Default.Search,
contentDescription = null, contentDescription = null,
tint = Color.Gray tint = Color.Gray,
modifier = Modifier.size(18.dp)
) )
} },
}, trailingIcon = {
shape = RoundedCornerShape(24.dp), Row(
colors = OutlinedTextFieldDefaults.colors( verticalAlignment = Alignment.CenterVertically
unfocusedContainerColor = Color(0xFFF5F5F5), ) {
focusedContainerColor = Color(0xFFF5F5F5), Icon(
unfocusedBorderColor = Color.Transparent, imageVector = Icons.Outlined.Image,
focusedBorderColor = Color.Transparent contentDescription = null,
), tint = Color.Gray,
modifier = Modifier modifier = Modifier.size(18.dp)
.fillMaxWidth() )
.height(50.dp) Spacer(modifier = Modifier.width(6.dp))
) Icon(
} imageVector = Icons.Outlined.LocationOn,
contentDescription = null,
tint = Color.Gray,
modifier = Modifier.size(18.dp)
)
}
},
shape = RoundedCornerShape(24.dp),
colors = OutlinedTextFieldDefaults.colors(
unfocusedContainerColor = Color(0xFFF5F5F5),
focusedContainerColor = Color(0xFFF5F5F5),
unfocusedBorderColor = Color.Transparent,
focusedBorderColor = Color.Transparent
),
singleLine = true,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
)
}
@Composable @Composable
private fun VibeFilterChipsSection( private fun VibeFilterChipsSection(
selectedColor: Color, selectedColor: Color,
@ -628,6 +638,7 @@ private val mockFeed = listOf(
full_name = "Alex Rivera", full_name = "Alex Rivera",
city = "Shanghai", city = "Shanghai",
country = "China", country = "China",
profile_image_url = null,
compatibilityPercentage = 95 compatibilityPercentage = 95
), ),
like_count = 12, like_count = 12,
@ -657,6 +668,7 @@ private val mockFeed = listOf(
full_name = "Sarah", full_name = "Sarah",
city = "Beijing", city = "Beijing",
country = "China", country = "China",
profile_image_url = null,
compatibilityPercentage = 88 compatibilityPercentage = 88
), ),
like_count = 0, like_count = 0,

50
app/src/main/java/com/example/dattingapp/homes/MeetScreen.kt

@ -4,6 +4,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.util.Log import android.util.Log
import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.Animatable
import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
@ -205,27 +206,38 @@ private fun ProfileCardItem(
} }
val defaultPainter = rememberVectorPainter(Icons.Default.Person) val defaultPainter = rememberVectorPainter(Icons.Default.Person)
AsyncImage( if (!photoUrl.isNullOrBlank()) {
model = ImageRequest.Builder(context) AsyncImage(
.data(photoUrl.takeIf { !it.isNullOrBlank() }) model = ImageRequest.Builder(context)
.apply { .data(photoUrl) // ← guaranteed non-null here
if (!token.isNullOrBlank()) { .apply {
val authHeader = if (token.startsWith("Bearer ", ignoreCase = true)) token else "Bearer $token" if (!token.isNullOrBlank()) {
addHeader("Authorization", authHeader) 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(), } else {
placeholder = defaultPainter, // No URL at all → show the default directly, Coil never runs
error = defaultPainter, Image(
fallback = defaultPainter, // Shows Icons.Default.Person immediately when photoUrl is null/blank painter = defaultPainter,
contentDescription = "Profile Image", contentDescription = "Profile Image",
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop
onError = { errorState -> )
Log.e("CoilStatus", "Failed to load image", errorState.result.throwable) }
}
)
// DARK GRADIENT OVERLAY // DARK GRADIENT OVERLAY
Box( Box(

686
app/src/main/java/com/example/dattingapp/homes/MyProfile.kt

@ -1,15 +1,21 @@
package com.example.dattingapp.homes package com.example.dattingapp.homes
import android.content.Intent
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.clickable
import androidx.compose.foundation.verticalScroll
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.TextSnippet
import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.MusicNote
import androidx.compose.material.icons.filled.TextSnippet
import androidx.compose.material.icons.outlined.Edit import androidx.compose.material.icons.outlined.Edit
import androidx.compose.material.icons.outlined.Settings import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material3.* import androidx.compose.material3.*
@ -20,104 +26,114 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import coil.compose.AsyncImage import coil.compose.AsyncImage
import com.example.dattingapp.LikeANdMatchActivity
import com.example.dattingapp.MasonryPostItem
import com.example.dattingapp.R import com.example.dattingapp.R
import com.example.dattingapp.ShowPostingActivity
import com.example.dattingapp.StaggeredFriendPostsGrid
import com.example.dattingapp.homes.profile.Author
import com.example.dattingapp.homes.profile.Media
import com.example.dattingapp.homes.profile.UserResponse import com.example.dattingapp.homes.profile.UserResponse
import com.example.dattingapp.homes.profile.Post
import com.example.dattingapp.homes.profile.ProfileData
import com.example.dattingapp.ui.theme.BrandMagenta import com.example.dattingapp.ui.theme.BrandMagenta
import com.example.dattingapp.ui.theme.BrandPurple import com.example.dattingapp.ui.theme.BrandPurple
import com.example.dattingapp.ui.theme.DattingAPPTheme import com.example.dattingapp.ui.theme.DattingAPPTheme
import com.example.dattingapp.ui.theme.textDark
import com.example.dattingapp.ui.theme.TextMuted import com.example.dattingapp.ui.theme.TextMuted
import com.example.dattingapp.homes.profile.ProfileData import com.example.dattingapp.ui.theme.textDark
import com.example.dattingapp.LikeANdMatchActivity import java.time.LocalDate
import android.content.Intent import java.time.Period
import android.util.Log import java.time.format.DateTimeFormatter
import androidx.compose.foundation.clickable
import androidx.compose.ui.platform.LocalContext // Helper function to calculate age from birth_date string (e.g., "1995-05-15")
import androidx.core.content.ContextCompat.startActivity private fun calculateAge(birthDateStr: String?): Int? {
if (birthDateStr.isNullOrBlank()) return null
// ============================================================ return try {
// MY PROFILE SCREEN val formatter = DateTimeFormatter.ISO_LOCAL_DATE
// ============================================================ val birthDate = LocalDate.parse(birthDateStr.take(10), formatter)
Period.between(birthDate, LocalDate.now()).years
} catch (e: Exception) {
null
}
}
@Composable @Composable
fun MyProfileScreen( fun MyProfileScreen(
profileResponse : UserResponse?, // Change from MyProfileData? to MyProfileResponse? profileResponse: UserResponse?,
isLoading: Boolean, isLoading: Boolean,
errorMessage: String?, errorMessage: String?,
onRetry: () -> Unit = {}, onRetry: () -> Unit = {},
onEditClick: () -> Unit = {}, onEditClick: () -> Unit = {},
onUpgradeClick: () -> Unit = {}, onUpgradeClick: () -> Unit = {},
onSettingsClick: () -> Unit = {}, onSettingsClick: () -> Unit = {},
onLikesClick: () -> Unit={}, onLikesClick: () -> Unit = {},
onLikedClick: () -> Unit={}, onLikedClick: () -> Unit = {},
onMatchClick: () -> Unit={} onMatchClick: () -> Unit = {}
) { ) {
// ========================================================
// FULL SCREEN SCROLL
// ========================================================
val context = LocalContext.current val context = LocalContext.current
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
val profile = profileResponse?.profile
val age = calculateAge(profile?.birth_date)
Column( Column(
modifier = Modifier.fillMaxSize().background(Color.White).verticalScroll(scrollState)) { modifier = Modifier
.fillMaxSize()
.background(Color.White)
.verticalScroll(scrollState)
) {
// ==================================================== // ====================================================
// HEADER // HEADER & COVER IMAGE
// ==================================================== // ====================================================
Box( Box(
modifier = Modifier.fillMaxWidth().height(260.dp) modifier = Modifier
.fillMaxWidth()
.height(260.dp)
) { ) {
// =================================================
// COVER IMAGE
// =================================================
Image( Image(
painter = painterResource(id = R.drawable.locationpermissionbg), painter = painterResource(id = R.drawable.locationpermissionbg),
contentDescription = "Cover Banner", contentDescription = "Cover Banner",
modifier = Modifier.fillMaxWidth().height(200.dp), modifier = Modifier
.fillMaxWidth()
.height(200.dp),
contentScale = ContentScale.Crop contentScale = ContentScale.Crop
) )
// =================================================
// SETTINGS BUTTON
// =================================================
// SETTINGS BUTTON
IconButton( IconButton(
onClick = onSettingsClick, onClick = onSettingsClick,
modifier = Modifier.align(Alignment.TopEnd) modifier = Modifier
.align(Alignment.TopEnd)
.padding(top = 16.dp, end = 16.dp) .padding(top = 16.dp, end = 16.dp)
.size(36.dp) .size(36.dp)
.clip(CircleShape) .clip(CircleShape)
.background(Color.Black.copy(alpha = 0.3f) .background(Color.Black.copy(alpha = 0.3f))
)
) { ) {
Icon( Icon(
imageVector = Icons.Outlined.Settings, imageVector = Icons.Outlined.Settings,
contentDescription = "Settings", contentDescription = "Settings",
tint = Color.White, tint = Color.White,
modifier = Modifier.size(20.dp) modifier = Modifier.size(20.dp)
) )
} }
// =================================================
// PROFILE IMAGE // PROFILE IMAGE & VERIFIED BADGE
// =================================================
Box( Box(
modifier = Modifier.align(Alignment.BottomStart) modifier = Modifier
.align(Alignment.BottomStart)
.padding(start = 24.dp) .padding(start = 24.dp)
.size(110.dp) .size(110.dp)
) { ) {
AsyncImage( AsyncImage(
// Access nested inner 'profile' first, then 'profileImageUrl' model = profile?.profile_image_url,
model = profileResponse?.profile?.profile_image_url,
contentDescription = "Profile Picture", contentDescription = "Profile Picture",
contentScale = ContentScale.Crop, contentScale = ContentScale.Crop,
placeholder = painterResource(id = R.drawable.locationpermissionbg), placeholder = painterResource(id = R.drawable.locationpermissionbg),
@ -128,15 +144,13 @@ fun MyProfileScreen(
.border(width = 4.dp, color = Color.White, shape = CircleShape) .border(width = 4.dp, color = Color.White, shape = CircleShape)
) )
// =================================================
// VERIFIED BADGE
// =================================================
Box( Box(
modifier = Modifier.align(Alignment.BottomEnd).size(28.dp).clip(CircleShape) modifier = Modifier
.align(Alignment.BottomEnd)
.size(28.dp)
.clip(CircleShape)
.background(BrandMagenta) .background(BrandMagenta)
.border(width = 2.dp, color = Color.White, shape = CircleShape .border(width = 2.dp, color = Color.White, shape = CircleShape),
),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
Icon( Icon(
@ -148,90 +162,103 @@ fun MyProfileScreen(
} }
} }
} }
// ==================================================== // ====================================================
// USER INFORMATION // USER INFORMATION SECTION
// ==================================================== // ====================================================
Column( Column(
modifier = Modifier
modifier = Modifier.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 24.dp, vertical = 8.dp) .padding(horizontal = 24.dp, vertical = 8.dp)
) { ) {
// ================================================= // NAME, AGE & EDIT BUTTON
// NAME + EDIT
// =================================================
Row( Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp) horizontalArrangement = Arrangement.SpaceBetween
) { ) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
text = if (age != null) "${profile?.full_name ?: ""}, $age" else (profile?.full_name ?: ""),
fontSize = 22.sp,
fontWeight = FontWeight.Bold,
color = textDark
)
}
Text( }
text = profileResponse?.profile?.full_name?:"",
fontSize = 22.sp,
fontWeight = FontWeight.Bold,
color = BrandMagenta
)
Spacer(modifier = Modifier.height(4.dp))
// EDIT BUTTON // LOCATION & STATUS
val locationText = listOfNotNull(profile?.city, profile?.country).joinToString(", ")
if (locationText.isNotBlank()) {
Text(
text = "📍 $locationText",
fontSize = 13.sp,
color = TextMuted
)
Spacer(modifier = Modifier.height(6.dp))
}
OutlinedButton( // BIO CONTAINER
onClick = onEditClick, if (!profile?.bio.isNullOrBlank()) {
modifier = Modifier.height(30.dp), Card(
contentPadding = PaddingValues(horizontal = 10.dp, vertical = 0.dp), modifier = Modifier.fillMaxWidth(),
border = ButtonDefaults shape = RoundedCornerShape(12.dp),
.outlinedButtonBorder colors = CardDefaults.cardColors(containerColor = Color(0xFFF9F9F9)),
.copy(width = 1.dp) border = CardDefaults.outlinedCardBorder().copy(width = 0.5.dp)
) { ) {
Icon(
imageVector = Icons.Outlined.Edit,
contentDescription = null,
tint = BrandMagenta,
modifier = Modifier.size(14.dp)
)
Spacer(modifier = Modifier.width(4.dp))
Text( Text(
text = "Edit", text = profile.bio!!,
fontSize = 12.sp, fontSize = 13.sp,
color = BrandMagenta, color = textDark,
fontWeight = FontWeight.Bold lineHeight = 18.sp,
modifier = Modifier.padding(12.dp)
) )
} }
Spacer(modifier = Modifier.height(10.dp))
} }
Spacer(modifier = Modifier.height(4.dp)) // INTERESTS CHIPS
// ================================================= if (!profile?.interests.isNullOrEmpty()) {
// BIO FlowRow(
// ================================================= modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(6.dp),
Log.d("my id","${profileResponse?.id}" ) verticalArrangement = Arrangement.spacedBy(6.dp)
Text( ) {
profile.interests.forEach { interest ->
text = profileResponse?.profile?.bio?:"", Surface(
fontSize = 13.sp, shape = RoundedCornerShape(16.dp),
color = TextMuted, color = BrandMagenta.copy(alpha = 0.1f)
lineHeight = 18.sp ) {
) Text(
text = interest,
color = BrandMagenta,
fontSize = 12.sp,
fontWeight = FontWeight.Medium,
modifier = Modifier.padding(horizontal = 12.dp, vertical = 6.dp)
)
}
}
}
}
} }
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(12.dp))
// ==================================================== // ====================================================
// PREMIUM BANNER // PREMIUM BANNER
// ==================================================== // ====================================================
Box( Box(
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp) modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
.clip(RoundedCornerShape(16.dp)) .clip(RoundedCornerShape(16.dp))
.background( .background(brush = Brush.horizontalGradient(colors = listOf(BrandMagenta, BrandPurple)))
brush = Brush.horizontalGradient(
colors = listOf(BrandMagenta, BrandPurple)
)
)
.padding(16.dp) .padding(16.dp)
) { ) {
Row( Row(
@ -240,42 +267,26 @@ fun MyProfileScreen(
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Column { Column {
Text( Text(
text = "VibeCheck Premium", text = "VibeCheck Premium",
color = Color.White, color = Color.White,
fontSize = 16.sp, fontSize = 16.sp,
fontWeight = FontWeight.Bold fontWeight = FontWeight.Bold
) )
Spacer(modifier = Modifier.height(2.dp))
Spacer(
modifier = Modifier.height(2.dp)
)
Text( Text(
text = "Unlock unlimited likes & more", text = "Unlock unlimited likes & more",
color = Color.White.copy(alpha = 0.8f), color = Color.White.copy(alpha = 0.8f),
fontSize = 12.sp fontSize = 12.sp
) )
} }
// UPGRADE BUTTON
Button( Button(
onClick = onUpgradeClick, onClick = onUpgradeClick,
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(containerColor = Color.White),
containerColor = Color.White
),
shape = RoundedCornerShape(20.dp), shape = RoundedCornerShape(20.dp),
contentPadding = PaddingValues( contentPadding = PaddingValues(horizontal = 14.dp, vertical = 4.dp)
horizontal = 14.dp,
vertical = 4.dp
)
) { ) {
Text( Text(
text = "Upgrade", text = "Upgrade",
color = BrandMagenta, color = BrandMagenta,
fontSize = 12.sp, fontSize = 12.sp,
@ -285,136 +296,98 @@ fun MyProfileScreen(
} }
} }
Spacer(modifier = Modifier.height(16.dp))
Spacer(
modifier = Modifier.height(16.dp)
)
// ==================================================== // ====================================================
// STATISTICS // STATISTICS CARDS
// ==================================================== // ====================================================
Row( Row(
modifier = Modifier
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), .fillMaxWidth()
.padding(horizontal = 16.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp) horizontalArrangement = Arrangement.spacedBy(8.dp)
) { ) {
StatCard( StatCard(
number = profileResponse?.liked_users_count?.toString() ?: "0", number = profileResponse?.liked_users_count?.toString() ?: "0",
label = "Likes", label = "Likes",
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
onClick = { onClick = {
val intent = Intent(context, LikeANdMatchActivity::class.java) val intent = Intent(context, LikeANdMatchActivity::class.java).apply {
putExtra("TYPE", "Likes")
}
context.startActivity(intent) context.startActivity(intent)
onLikesClick() onLikesClick()
} }
) )
StatCard( StatCard(
number = profileResponse?.liked_by_users_count?.toString() ?: "0", number = profileResponse?.liked_by_users_count?.toString() ?: "0",
label = "Liked", label = "Liked",
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
onClick = { /* Optional: Handle Matches click */ } onClick = {
val intent = Intent(context, LikeANdMatchActivity::class.java).apply {
putExtra("TYPE", "Liked")
}
context.startActivity(intent)
onLikedClick()
}
) )
// StatCard(
// number = "Top",
// label = "Match",
// numberColor = BrandMagenta,
// modifier = Modifier.weight(1f)
// )
StatCard( StatCard(
number = profileResponse?.matches_count?.toString() ?: "0", number = profileResponse?.matches_count?.toString() ?: "0",
label = "Matches", label = "Matches",
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
onClick = { /* Optional: Handle Matches click */ } onClick = {
val intent = Intent(context, LikeANdMatchActivity::class.java).apply {
putExtra("TYPE", "Matches")
}
context.startActivity(intent)
onMatchClick()
}
) )
} }
Spacer(
modifier = Modifier.height(16.dp)
)
ProfileMediaGrid() Spacer(modifier = Modifier.height(20.dp))
Spacer( // ====================================================
modifier = Modifier.height(30.dp) // ALREADY POSTED / DYNAMIC POSTS SECTION
// ====================================================
Text(
text = "Posted",
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
color = textDark,
modifier = Modifier.padding(horizontal = 16.dp)
) )
} Spacer(modifier = Modifier.height(10.dp))
}
// ============================================================
// PROFILE MEDIA GRID
// ============================================================
@Composable
private fun ProfileMediaGrid() {
Column(
modifier = Modifier.fillMaxWidth().padding(2.dp)
) {
// 6 rows × 3 columns = 18 images
repeat(6) { rowIndex ->
Row(
modifier = Modifier.fillMaxWidth()
) {
repeat(3) { columnIndex ->
val imageIndex = rowIndex * 3 + columnIndex
ProfilePostsGrid(posts = profileResponse?.posts ?: emptyList())
Image( Spacer(modifier = Modifier.height(30.dp))
painter = painterResource(
id = R.drawable.locationpermissionbg
),
contentDescription = "Profile Image $imageIndex",
modifier = Modifier.weight(1f).aspectRatio(1f).padding(1.dp),
contentScale = ContentScale.Crop
)
}
}
}
} }
} }
// ============================================================ // ============================================================
// STAT CARD // STAT CARD
// ============================================================ // ============================================================
@Composable @Composable
private fun StatCard( private fun StatCard(
number: String, number: String,
label: String, label: String,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
numberColor: Color = textDark, numberColor: Color = textDark,
onClick:()->Unit onClick: () -> Unit
) { ) {
Card( Card(
modifier = modifier.clickable { onClick() }, modifier = modifier.clickable { onClick() },
shape = RoundedCornerShape(12.dp), shape = RoundedCornerShape(12.dp),
colors = CardDefaults.cardColors(containerColor = Color(0xFFFAFAFA)),
colors = CardDefaults.cardColors( border = CardDefaults.outlinedCardBorder().copy(width = 0.5.dp)
containerColor = Color(0xFFFAFAFA)
),
border =
CardDefaults.outlinedCardBorder()
.copy(width = 0.5.dp)
) { ) {
Column( Column(
modifier = Modifier.fillMaxWidth().padding(vertical = 12.dp), modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Text( Text(
@ -423,10 +396,7 @@ private fun StatCard(
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
color = numberColor color = numberColor
) )
Spacer( Spacer(modifier = Modifier.height(2.dp))
modifier = Modifier.height(2.dp)
)
Text( Text(
text = label, text = label,
fontSize = 11.sp, fontSize = 11.sp,
@ -438,39 +408,299 @@ private fun StatCard(
// ============================================================ // ============================================================
// PREVIEW // STAGGERED PROFILE POSTS GRID (Matches your custom Masonry layout)
// ============================================================
@Composable
private fun ProfilePostsGrid(posts: List<Post>) {
if (posts.isEmpty()) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(120.dp),
contentAlignment = Alignment.Center
) {
Text(text = "No posts yet", color = TextMuted, fontSize = 14.sp)
}
return
}
// Distribute posts into two columns
val columns = remember(posts) {
val col1 = mutableListOf<Post>()
val col2 = mutableListOf<Post>()
posts.forEachIndexed { index, post ->
if (index % 2 == 0) {
col1.add(post)
} else {
col2.add(post)
}
}
Pair(col1, col2)
}
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
horizontalArrangement = Arrangement.spacedBy(6.dp)
) {
// Column 1
Column(
modifier = Modifier.weight(1f),
verticalArrangement = Arrangement.spacedBy(6.dp)
) {
columns.first.forEachIndexed { idx, post ->
val aspectRatio = if (idx % 2 == 0) 0.8f else 1.2f
MasonryProfilePostItem(post = post, aspectRatio = aspectRatio)
}
}
// Column 2
Column(
modifier = Modifier.weight(1f),
verticalArrangement = Arrangement.spacedBy(6.dp)
) {
columns.second.forEachIndexed { idx, post ->
val aspectRatio = if (idx % 2 == 0) 1.2f else 0.8f
MasonryProfilePostItem(post = post, aspectRatio = aspectRatio)
}
}
}
}
@Composable
private fun MasonryProfilePostItem(post: Post, aspectRatio: Float) {
val context = LocalContext.current
val primaryMedia = post.media.firstOrNull()?.url
val isImage = post.post_type.equals("image", ignoreCase = true) || !primaryMedia.isNullOrEmpty()
Card(
shape = RoundedCornerShape(12.dp),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp),
modifier = Modifier
.fillMaxWidth()
.aspectRatio(aspectRatio)
.clickable {
val intent = Intent(context, ShowPostingActivity::class.java).apply {
putExtra("Post_ID", post.id)
}
context.startActivity(intent)
}
) {
Box(
modifier = Modifier
.fillMaxSize()
) {
if (isImage && !primaryMedia.isNullOrEmpty()) {
AsyncImage(
model = primaryMedia,
contentDescription = "Post Image",
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
// Dark Gradient Scrim for text readability over images
Box(
modifier = Modifier
.fillMaxSize()
.background(
Brush.verticalGradient(
colors = listOf(Color.Transparent, Color.Black.copy(alpha = 0.65f)),
startY = 100f
)
)
)
// Image metadata overlay
Column(
modifier = Modifier
.align(Alignment.BottomStart)
.padding(8.dp),
verticalArrangement = Arrangement.spacedBy(2.dp)
) {
if (!post.feeling.isNullOrBlank()) {
Text(
text = post.feeling,
color = Color.White.copy(alpha = 0.9f),
fontSize = 9.sp,
fontWeight = FontWeight.Bold
)
}
if (!post.content.isNullOrBlank()) {
Text(
text = post.content,
color = Color.White,
fontSize = 11.sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
}
} else {
// Text / Status Card Design
Column(
modifier = Modifier
.fillMaxSize()
.padding(10.dp),
verticalArrangement = Arrangement.SpaceBetween
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(3.dp)
) {
Icon(
imageVector = when (post.post_type.lowercase()) {
"music" -> Icons.Default.MusicNote
else -> Icons.Default.TextSnippet
},
contentDescription = null,
tint = Color.White,
modifier = Modifier.size(10.dp)
)
Text(
text = post.post_type.uppercase(),
color = Color.White.copy(alpha = 0.9f),
fontSize = 7.sp,
fontWeight = FontWeight.ExtraBold
)
}
}
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
if (!post.feeling.isNullOrBlank()) {
Surface(
shape = RoundedCornerShape(6.dp),
color = Color.White.copy(alpha = 0.2f)
) {
Text(
text = "feeling ${post.feeling}",
color = Color.White,
fontSize = 7.sp,
modifier = Modifier.padding(horizontal = 4.dp, vertical = 2.dp),
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
}
Text(
text = post.content ?: "",
color = Color.White,
fontSize = 11.sp,
fontWeight = FontWeight.SemiBold,
maxLines = 3,
overflow = TextOverflow.Ellipsis,
lineHeight = 14.sp
)
}
// Footer Likes
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(2.dp)
) {
Icon(
imageVector = Icons.Default.Favorite,
contentDescription = null,
tint = Color.White.copy(alpha = 0.8f),
modifier = Modifier.size(9.dp)
)
Text(
text = "${post.like_count}",
color = Color.White.copy(alpha = 0.8f),
fontSize = 8.sp
)
}
}
}
}
}
}
// ============================================================
// PREVIEWS
// ============================================================ // ============================================================
@Preview(showBackground = true, showSystemUi = true) @Preview(showBackground = true, showSystemUi = true)
@Composable @Composable
fun MyProfileScreenSuccessPreview() { fun MyProfileScreenSuccessPreview() {
DattingAPPTheme { DattingAPPTheme {
// Mock UserResponse matching your backend model hierarchy // Mock UserResponse matching your backend model structure
val mockUserResponse = UserResponse( val mockUserResponse = UserResponse(
id = 1, id = 1,
email_or_phone = "alex.dev@example.com", email_or_phone = "elena@example.com",
status = "active", status = "active",
profile = ProfileData( profile = ProfileData(
full_name = "Alex Morgan", full_name = "Elena",
gender = "Male", gender = "Female",
birth_date = "1995-05-15", birth_date = "2002-04-12", // 24 years old
city = "New York", city = "New York",
county = "Manhattan", county = null,
country = "USA", country = "USA",
relationship_goal = "Long-term partnership", relationship_goal = "Long-term partnership",
bio = "Adventure seeker, dog lover, and amateur chef. Let's find a vibe!", bio = "\"Always looking for the best flat white in the city. Amateur photographer, professional dog petter...\"",
profile_image_url = "https://picsum.photos/300/300", profile_image_url = "https://picsum.photos/300/300",
video_url = null, video_url = null,
interests = listOf("Hiking", "Cooking", "Photography") interests = listOf("Photography", "Dogs", "Coffee Shop Lover", "Art Galleries")
), ),
created_at = "2026-01-01", created_at = "2026-01-01",
posts = emptyList(), posts = listOf(
Post(
id = 101,
content = "Enjoying the art exhibition!",
post_type = "image",
content_format = "standard",
feeling = "Happy",
location = null,
author = Author(1, "Elena", "New York", "USA", 98),
like_count = 12,
comment_count = 3,
liked_by_me = false,
media = listOf(
Media(
1,
"image",
"image/jpeg",
1024,
1,
"https://picsum.photos/400/400?random=1"
),
Media(2, "image", "image/jpeg", 1024, 2, "https://picsum.photos/400/400?random=2"),
Media(3, "image", "image/jpeg", 1024, 3, "https://picsum.photos/400/400?random=3")
),
created_at = "2026-02-10"
),
Post(
id = 102,
content = "Weekend coffee vibes ☕",
post_type = "image",
content_format = "standard",
feeling = "Relaxed",
location = null,
author = Author(1, "Elena", "New York", "USA", 98),
like_count = 25,
comment_count = 5,
liked_by_me = false,
media = listOf(
Media(4, "image", "image/jpeg", 1024, 1, "https://picsum.photos/400/400?random=4"),
Media(5, "image", "image/jpeg", 1024, 2, "https://picsum.photos/400/400?random=5"),
Media(6, "image", "image/jpeg", 1024, 3, "https://picsum.photos/400/400?random=6")
),
created_at = "2026-02-12"
)
),
liked_users = emptyList(), liked_users = emptyList(),
liked_by_users = emptyList(), liked_by_users = emptyList(),
matches = emptyList(), matches = emptyList(),
liked_users_count = 24, liked_users_count = 42,
liked_by_users_count = 12, liked_by_users_count = 128,
matches_count = 8 matches_count = 18
) )
MyProfileScreen( MyProfileScreen(

11
app/src/main/java/com/example/dattingapp/homes/networkandapi/HomeApiService.kt

@ -69,9 +69,20 @@ interface HomeApiService {
): Response<UserResponse> ): Response<UserResponse>
@GET("api/v1/users/me/liked") @GET("api/v1/users/me/liked")
suspend fun getLikeUsers(
): Response<List<LikedUserResponse>>
@GET("/api/v1/users/me/likes")
suspend fun getLikedUsers( suspend fun getLikedUsers(
): Response<List<LikedUserResponse>> ): Response<List<LikedUserResponse>>
@GET("/api/v1/matches")
suspend fun getMatches(
@Query("limit") limit: Int = 20,
@Query("offset") offset: Int = 0
): Response<List<LikedUserResponse>>
@GET("api/v1/explore/posts/{post_id}") @GET("api/v1/explore/posts/{post_id}")
suspend fun getPostById( suspend fun getPostById(
@Path("post_id") postId: Int @Path("post_id") postId: Int

48
app/src/main/java/com/example/dattingapp/homes/networkandapi/HomeViewModelClass.kt

@ -534,49 +534,62 @@ sealed interface LikedUiState {
class LikedViewModel : ViewModel() { class LikedViewModel : ViewModel() {
private val _likeUiState = MutableStateFlow<LikedUiState>(LikedUiState.Idle) // ✅ three separate states, one per list type
val likeUiState: StateFlow<LikedUiState> = _likeUiState.asStateFlow() private val _likedUiState = MutableStateFlow<LikedUiState>(LikedUiState.Idle) // users who liked ME
val likedUiState: StateFlow<LikedUiState> = _likedUiState.asStateFlow()
fun likedResponse(context: Context) { private val _likesUiState = MutableStateFlow<LikedUiState>(LikedUiState.Idle) // users I liked
if (_likeUiState.value is LikedUiState.Loading) return val likesUiState: StateFlow<LikedUiState> = _likesUiState.asStateFlow()
private val _matchesUiState = MutableStateFlow<LikedUiState>(LikedUiState.Idle) // matches
val matchesUiState: StateFlow<LikedUiState> = _matchesUiState.asStateFlow()
fun likedResponse(context: Context, type: String) {
val appContext = context.applicationContext 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 { viewModelScope.launch {
_likeUiState.value = LikedUiState.Loading targetFlow.value = LikedUiState.Loading
if (TokenManager.getInstance(appContext).getAccessToken().isNullOrBlank()) { if (TokenManager.getInstance(appContext).getAccessToken().isNullOrBlank()) {
Log.e("MeetApi", "No access token in user_tokens preferences") 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 return@launch
} }
try { try {
// Returns CreatePostResponse directly val createdPost = when (type) {
val createdPost = HomeNetworkModule "Likes" -> HomeNetworkModule.getApiService(appContext).getLikeUsers()
.getApiService(appContext) "Liked" -> HomeNetworkModule.getApiService(appContext).getLikedUsers()
.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) { if (createdPost.isSuccessful && createdPost.body() != null) {
_likeUiState.value = LikedUiState.Success(createdPost.body()!!) // Use .body() here! targetFlow.value = LikedUiState.Success(createdPost.body()!!)
} else { } 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) { } catch (e: HttpException) {
// Handle HTTP errors via HttpException automatically thrown by Retrofit
val message = when (e.code()) { val message = when (e.code()) {
401 -> "Authentication failed. Please log in again." 401 -> "Authentication failed. Please log in again."
403 -> "The server refused access to this profile." 403 -> "The server refused access to this profile."
404 -> "User profile was not found." 404 -> "User profile was not found."
else -> "Request failed: HTTP ${e.code()}." else -> "Request failed: HTTP ${e.code()}."
} }
_likeUiState.value = LikedUiState.Error(message) targetFlow.value = LikedUiState.Error(message)
} catch (e: Exception) { } catch (e: Exception) {
Log.e("MeetApi", "Unexpected request failure", e) 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", full_name = currentUserName ?: "You",
city = null, city = null,
country = null, country = null,
profile_image_url = null,
compatibilityPercentage = null compatibilityPercentage = null
), ),
createdAt = "Just now" createdAt = "Just now"

23
app/src/main/java/com/example/dattingapp/homes/networkandapi/TokenManager.kt

@ -11,7 +11,13 @@ class TokenManager private constructor(context: Context) {
Context.MODE_PRIVATE Context.MODE_PRIVATE
) )
fun saveTokens(accessToken: String, refreshToken: String?,userId: Int,currenUserName:String?) { private val prefProfile =
context.applicationContext.getSharedPreferences(
PREF_NAME,
Context.MODE_PRIVATE
)
fun saveTokens(accessToken: String, refreshToken: String?) {
val cleanToken = accessToken.trim() val cleanToken = accessToken.trim()
.replace( .replace(
Regex("^Bearer\\s+", RegexOption.IGNORE_CASE), Regex("^Bearer\\s+", RegexOption.IGNORE_CASE),
@ -22,8 +28,17 @@ class TokenManager private constructor(context: Context) {
val saved = preferences.edit() val saved = preferences.edit()
.putString(KEY_ACCESS_TOKEN, cleanToken) .putString(KEY_ACCESS_TOKEN, cleanToken)
.putString(KEY_REFRESH_TOKEN, refreshToken) .putString(KEY_REFRESH_TOKEN, refreshToken)
.commit()
// Do not log the token itself.
Log.d("TokenManager", "Tokens saved: $saved")
}
fun saveProfile(userId: Int,currenUserName:String?,profile_image_url:String?) {
val saved = preferences.edit()
.putInt("user_id", userId) .putInt("user_id", userId)
.putString("currenUserName", currenUserName) .putString("currenUserName", currenUserName)
.putString("profile_image_url", profile_image_url)
.commit() .commit()
// Do not log the token itself. // Do not log the token itself.
@ -32,11 +47,13 @@ class TokenManager private constructor(context: Context) {
fun getUserId(): Int { fun getUserId(): Int {
return preferences.getInt("user_id", -1) return prefProfile.getInt("user_id", -1)
} }
fun currentUserName(): String? = preferences.getString("full_name", null) fun currentUserName(): String? = prefProfile.getString("currenUserName", null)
fun currentProfileImage(): String? = prefProfile.getString("profile_image_url", null)
fun getAccessToken(): String? { fun getAccessToken(): String? {
return preferences.getString(KEY_ACCESS_TOKEN, null) return preferences.getString(KEY_ACCESS_TOKEN, null)

4
app/src/main/java/com/example/dattingapp/registration/RegisterRequest.kt

@ -74,5 +74,7 @@ data class LoginUser(
data class LoginProfile( data class LoginProfile(
@SerializedName("full_name") @SerializedName("full_name")
val full_name: String? = null val full_name: String? = null,
@SerializedName("profile_image_url")
val profile_image_url: String? = null
) )

8
app/src/main/java/com/example/dattingapp/registration/RegistrationScreen.kt

@ -80,6 +80,7 @@ import android.content.pm.PackageManager
import android.location.LocationManager import android.location.LocationManager
import android.os.Looper import android.os.Looper
import android.Manifest import android.Manifest
import android.util.Log
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@ -100,6 +101,8 @@ import androidx.compose.material.icons.filled.LocationOn
// Permission check // Permission check
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.example.dattingapp.homes.networkandapi.TokenManager
class RegistrationScreen : ComponentActivity() { class RegistrationScreen : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge() enableEdgeToEdge()
@ -156,7 +159,12 @@ fun RegistrationFlowContainer(
when (val state = uiState) { when (val state = uiState) {
is RegistrationUiState.Success -> { is RegistrationUiState.Success -> {
Toast.makeText(context, "Registration Successful!", Toast.LENGTH_SHORT).show() Toast.makeText(context, "Registration Successful!", Toast.LENGTH_SHORT).show()
val tokenManager = TokenManager.getInstance(context)
tokenManager.saveTokens(
accessToken = state.response.accessToken,
refreshToken = state.response.refreshToken
)
// Navigate to UploadProfileImageActivity and finish flow // Navigate to UploadProfileImageActivity and finish flow
val intent = Intent(context, UploadProfileImageActivity::class.java).apply { val intent = Intent(context, UploadProfileImageActivity::class.java).apply {
putExtra("ACCESS_TOKEN", state.response.accessToken) putExtra("ACCESS_TOKEN", state.response.accessToken)

2
app/src/main/java/com/example/dattingapp/ui/theme/Color.kt

@ -113,7 +113,7 @@ colors = listOf(
Color(0xFF6B00B0) // Deep Purple Color(0xFF6B00B0) // Deep Purple
) )
) )
val purpleButtonColor = Color(0xFF6B00F5) val purpleButtonColor = Color(0x236B00F5)
// Same post id always gives the same color // Same post id always gives the same color
val OverlayShadow = Shadow( val OverlayShadow = Shadow(

Loading…
Cancel
Save