From 58b14651e810643eea4e14f51fb26c68b3370284 Mon Sep 17 00:00:00 2001 From: osman160128 Date: Fri, 16 Oct 2026 15:32:56 +0600 Subject: [PATCH] feed --- .../com/example/dattingapp/FriendProfile.kt | 184 ++--- .../dattingapp/LikeANdMatchActivity.kt | 47 +- .../example/dattingapp/Login/LoginActivity.kt | 12 +- .../example/dattingapp/homes/ExploreScreen.kt | 113 +-- .../com/example/dattingapp/homes/MyProfile.kt | 684 ++++++++++++------ .../homes/networkandapi/HomeViewModelClass.kt | 8 +- .../homes/networkandapi/TokenManager.kt | 23 +- .../registration/RegistrationScreen.kt | 8 + 8 files changed, 689 insertions(+), 390 deletions(-) diff --git a/app/src/main/java/com/example/dattingapp/FriendProfile.kt b/app/src/main/java/com/example/dattingapp/FriendProfile.kt index 2ac0b34..bb8d4e0 100644 --- a/app/src/main/java/com/example/dattingapp/FriendProfile.kt +++ b/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.material3.* import androidx.compose.runtime.* +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -140,10 +141,10 @@ fun FriendProfileScreen( } // ✅ turn each into a set of ids - val likedMeIds = (likesState as? LikedUiState.Success) + val iLikedIds = (likesState as? LikedUiState.Success) ?.LikeData?.map { it.id }?.toSet() ?: emptySet() - val iLikedIds = (likedState as? LikedUiState.Success) + val likedMeIds = (likedState as? LikedUiState.Success) ?.LikeData?.map { it.id }?.toSet() ?: emptySet() val matchIds = (matchesState as? LikedUiState.Success) @@ -154,6 +155,12 @@ fun FriendProfileScreen( 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) { calculateAge(friendProfileData.birth_date) } @@ -303,8 +310,7 @@ fun FriendProfileScreen( ) } - - // Action Buttons Row + //action button Row( modifier = Modifier .fillMaxWidth() @@ -312,110 +318,124 @@ fun FriendProfileScreen( horizontalArrangement = Arrangement.spacedBy(10.dp), verticalAlignment = Alignment.CenterVertically ) { - // 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) + // Message — card style, no background color + // Message — enabled only when matched, grayed out otherwise + Card( + onClick = onMessageClick, + enabled = isMatch, // ✅ disabled when not matched + modifier = Modifier + .weight(1f) + .height(48.dp), + shape = RoundedCornerShape(10.dp), + colors = CardDefaults.cardColors( + containerColor = if (isMatch) Color.White else Color(0xFFF0F0F0), + disabledContainerColor = Color(0xFFF0F0F0) + ), + elevation = CardDefaults.cardElevation( + defaultElevation = if (isMatch) 4.dp else 0.dp + ) + ) { + Row( + modifier = Modifier.fillMaxSize(), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically ) { - 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 - ) - } + 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 + ) } } - // ❤️ 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) - ) - } - } - // 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) - ) - } + // ❤️ 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 = { + onLikeClick() + handleLikeAndDislikeAction(context, "right", friendProfileData, swipeViewModel) + localLiked = true // ✅ disable after first click + }, + enabled = !likeDisabled, + modifier = Modifier.size(48.dp), + shape = RoundedCornerShape(10.dp), + colors = CardDefaults.cardColors( + containerColor = if (heLikedMe) Color(0xFFE53935) else Color.White, + disabledContainerColor = if (heLikedMe) Color(0xFFE53935) else Color(0xFFF0F0F0) + ), + elevation = CardDefaults.cardElevation( + 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) + ) } } - // Cancel — inside a card, always visible + // Super Like — card style + 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 = 2.dp) + ) { + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Icon( + imageVector = Icons.Default.Star, + contentDescription = "Favorite", + tint = textDark, + modifier = Modifier.size(20.dp) + ) + } + } + + // Cancel — card style, always visible + // Cancel — clicking it re-enables the Like button Card( onClick = { onCancelClick() handleLikeAndDislikeAction(context, "left", friendProfileData, swipeViewModel) + localLiked = false // ✅ Like button works again }, modifier = Modifier.size(48.dp), shape = RoundedCornerShape(10.dp), colors = CardDefaults.cardColors(containerColor = Color.White), - elevation = CardDefaults.cardElevation(defaultElevation = 4.dp) + elevation = CardDefaults.cardElevation(defaultElevation = 2.dp) ) { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Icon( imageVector = Icons.Default.Close, contentDescription = "Dislike", tint = textDark, - modifier = Modifier.size(22.dp) + modifier = Modifier.size(20.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 7b54302..1e69f69 100644 --- a/app/src/main/java/com/example/dattingapp/LikeANdMatchActivity.kt +++ b/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.shape.RoundedCornerShape 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.LocationOn import androidx.compose.material3.* @@ -54,18 +56,50 @@ class LikeANdMatchActivity : ComponentActivity() { DattingAPPTheme { val likedViewModel: LikedViewModel = viewModel() val context = LocalContext.current - val type = intent.getStringExtra("TYPE") ?: "liked" + val type = intent.getStringExtra("TYPE") ?: "Likes" - // Collect state from ViewModel - val uiState by likedViewModel.likesUiState.collectAsState() + // Dynamically collect the correct StateFlow based on the 'type' + val uiState by when (type) { + "Likes" -> likedViewModel.likesUiState.collectAsState() + "Liked" -> likedViewModel.likedUiState.collectAsState() + else -> likedViewModel.matchesUiState.collectAsState() + } // Trigger network call once when screen loads LaunchedEffect(Unit) { - likedViewModel.likedResponse(context,type) + likedViewModel.likedResponse(context, type) } Scaffold( 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 -> Box( modifier = Modifier @@ -79,7 +113,7 @@ class LikeANdMatchActivity : ComponentActivity() { } is LikedUiState.Success -> { ProfileGrid( - context =context, + context = context, likedResponse = state.LikeData, isLoading = false, errorMessage = null @@ -96,7 +130,7 @@ class LikeANdMatchActivity : ComponentActivity() { color = MaterialTheme.colorScheme.error, fontWeight = FontWeight.Medium ) - Button(onClick = { likedViewModel.likedResponse(context,"like") }) { + Button(onClick = { likedViewModel.likedResponse(context, type) }) { Text("Retry") } } @@ -108,7 +142,6 @@ class LikeANdMatchActivity : ComponentActivity() { } } } - // 1. Define ProfileCard FIRST so ProfileGrid can reference it without issue @Composable fun ProfileCard(context: Context, likedProfile: LikedUserResponse, modifier: Modifier = Modifier, 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 e90d71f..6ed2465 100644 --- a/app/src/main/java/com/example/dattingapp/Login/LoginActivity.kt +++ b/app/src/main/java/com/example/dattingapp/Login/LoginActivity.kt @@ -274,12 +274,16 @@ fun LoginScreenContent( Log.d("useridlogin","$id") tokenManager.saveTokens( accessToken = loginData.accessToken ?: "", - refreshToken = loginData.refreshToken ?: "", - userId = loginData.user?.id ?: -1, - currenUserName = loginData.user?.profile?.full_name, - profile_image_url=loginData.user?.profile?.profile_image_url + refreshToken = loginData.refreshToken ?: "" ) + 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() onLoginSuccess() } else { 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 a4591ee..c7a39e7 100644 --- a/app/src/main/java/com/example/dattingapp/homes/ExploreScreen.kt +++ b/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.layout.ContentScale import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -42,12 +43,14 @@ import androidx.media3.common.Player import androidx.media3.exoplayer.ExoPlayer import androidx.media3.ui.PlayerView import coil.compose.AsyncImage +import com.example.dattingapp.R import com.example.dattingapp.ShowPostingActivity import com.example.dattingapp.dataclass.Author import com.example.dattingapp.dataclass.Location import com.example.dattingapp.dataclass.MediaItem import com.example.dattingapp.dataclass.ShowPostResponse 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.ui.theme.DattingAPPTheme import com.example.dattingapp.ui.theme.OverlayShadow @@ -64,15 +67,6 @@ data class VibeCategory( 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 = emptyList() -) data class UserMatch( val id: String, @@ -132,6 +126,10 @@ fun VibeCheckHomeScreen( private fun VibeCheckTopAppBar( primaryColor: Color ) { + val context = LocalContext.current + val tokenManager = remember { TokenManager.getInstance(context) } + val currentUserName = remember { tokenManager.currentUserName() } + val currentProfileImage = remember { tokenManager.currentProfileImage() } Row( modifier = Modifier .fillMaxWidth() @@ -147,17 +145,22 @@ private fun VibeCheckTopAppBar( } 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 - .size(32.dp) - .clip(CircleShape) - .background(Color.Gray) + .size(40.dp) + .clip(CircleShape), + contentScale = ContentScale.Crop ) - Spacer(modifier = Modifier.width(8.dp)) + Spacer(modifier = Modifier.width(2.dp)) Text( - text = "VibeCheck", + text = currentUserName?:"", color = primaryColor, fontSize = 20.sp, fontWeight = FontWeight.Bold @@ -177,47 +180,53 @@ private fun VibeCheckTopAppBar( private fun SearchBarSection() { var searchText by remember { mutableStateOf("") } - OutlinedTextField( - value = searchText, - onValueChange = { searchText = it }, - placeholder = { - Text(text = "Search", color = Color.Gray) - }, - 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)) + OutlinedTextField( + value = searchText, + onValueChange = { searchText = it }, + placeholder = { + Text(text = "Search", color = Color.Gray, fontSize = 13.sp) + }, + leadingIcon = { Icon( - imageVector = Icons.Outlined.LocationOn, + imageVector = Icons.Default.Search, contentDescription = null, - tint = Color.Gray + 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 - ), - modifier = Modifier - .fillMaxWidth() - .height(50.dp) - ) -} + }, + trailingIcon = { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = Icons.Outlined.Image, + contentDescription = null, + tint = Color.Gray, + modifier = Modifier.size(18.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 private fun VibeFilterChipsSection( selectedColor: Color, 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 886dac7..8859457 100644 --- a/app/src/main/java/com/example/dattingapp/homes/MyProfile.kt +++ b/app/src/main/java/com/example/dattingapp/homes/MyProfile.kt @@ -1,15 +1,21 @@ package com.example.dattingapp.homes +import android.content.Intent import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll 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.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.Settings import androidx.compose.material3.* @@ -20,105 +26,114 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource 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.unit.dp import androidx.compose.ui.unit.sp import coil.compose.AsyncImage +import com.example.dattingapp.LikeANdMatchActivity +import com.example.dattingapp.MasonryPostItem 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.Post +import com.example.dattingapp.homes.profile.ProfileData import com.example.dattingapp.ui.theme.BrandMagenta import com.example.dattingapp.ui.theme.BrandPurple 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.homes.profile.ProfileData -import com.example.dattingapp.LikeANdMatchActivity -import android.content.Intent -import android.util.Log -import androidx.compose.foundation.clickable -import androidx.compose.ui.platform.LocalContext -import androidx.core.content.ContextCompat.startActivity - -// ============================================================ -// MY PROFILE SCREEN -// ============================================================ - +import com.example.dattingapp.ui.theme.textDark +import java.time.LocalDate +import java.time.Period +import java.time.format.DateTimeFormatter + +// Helper function to calculate age from birth_date string (e.g., "1995-05-15") +private fun calculateAge(birthDateStr: String?): Int? { + if (birthDateStr.isNullOrBlank()) return null + return try { + 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 fun MyProfileScreen( - profileResponse : UserResponse?, // Change from MyProfileData? to MyProfileResponse? + profileResponse: UserResponse?, isLoading: Boolean, errorMessage: String?, onRetry: () -> Unit = {}, onEditClick: () -> Unit = {}, onUpgradeClick: () -> Unit = {}, onSettingsClick: () -> Unit = {}, - onLikesClick: () -> Unit={}, - onLikedClick: () -> Unit={}, - onMatchClick: () -> Unit={} - - + onLikesClick: () -> Unit = {}, + onLikedClick: () -> Unit = {}, + onMatchClick: () -> Unit = {} ) { - // ======================================================== - // FULL SCREEN SCROLL - // ======================================================== val context = LocalContext.current val scrollState = rememberScrollState() + + val profile = profileResponse?.profile + val age = calculateAge(profile?.birth_date) + Column( - modifier = Modifier.fillMaxSize().background(Color.White).verticalScroll(scrollState)) { + modifier = Modifier + .fillMaxSize() + .background(Color.White) + .verticalScroll(scrollState) + ) { // ==================================================== - // HEADER + // HEADER & COVER IMAGE // ==================================================== Box( - modifier = Modifier.fillMaxWidth().height(260.dp) + modifier = Modifier + .fillMaxWidth() + .height(260.dp) ) { - // ================================================= - // COVER IMAGE - // ================================================= Image( painter = painterResource(id = R.drawable.locationpermissionbg), contentDescription = "Cover Banner", - modifier = Modifier.fillMaxWidth().height(200.dp), + modifier = Modifier + .fillMaxWidth() + .height(200.dp), contentScale = ContentScale.Crop ) - // ================================================= - // SETTINGS BUTTON - // ================================================= + // SETTINGS BUTTON IconButton( onClick = onSettingsClick, - modifier = Modifier.align(Alignment.TopEnd) + modifier = Modifier + .align(Alignment.TopEnd) .padding(top = 16.dp, end = 16.dp) .size(36.dp) .clip(CircleShape) - .background(Color.Black.copy(alpha = 0.3f) - ) + .background(Color.Black.copy(alpha = 0.3f)) ) { - Icon( - imageVector = Icons.Outlined.Settings, - contentDescription = "Settings", tint = Color.White, modifier = Modifier.size(20.dp) ) } - // ================================================= - // PROFILE IMAGE - // ================================================= + + // PROFILE IMAGE & VERIFIED BADGE Box( - modifier = Modifier.align(Alignment.BottomStart) + modifier = Modifier + .align(Alignment.BottomStart) .padding(start = 24.dp) .size(110.dp) ) { - - AsyncImage( - // Access nested inner 'profile' first, then 'profileImageUrl' - model = profileResponse?.profile?.profile_image_url, + model = profile?.profile_image_url, contentDescription = "Profile Picture", contentScale = ContentScale.Crop, placeholder = painterResource(id = R.drawable.locationpermissionbg), @@ -129,15 +144,13 @@ fun MyProfileScreen( .border(width = 4.dp, color = Color.White, shape = CircleShape) ) - // ================================================= - // VERIFIED BADGE - // ================================================= Box( - modifier = Modifier.align(Alignment.BottomEnd).size(28.dp).clip(CircleShape) + modifier = Modifier + .align(Alignment.BottomEnd) + .size(28.dp) + .clip(CircleShape) .background(BrandMagenta) - .border(width = 2.dp, color = Color.White, shape = CircleShape - ), - + .border(width = 2.dp, color = Color.White, shape = CircleShape), contentAlignment = Alignment.Center ) { Icon( @@ -149,90 +162,103 @@ fun MyProfileScreen( } } } + // ==================================================== - // USER INFORMATION + // USER INFORMATION SECTION // ==================================================== - Column( - - modifier = Modifier.fillMaxWidth() + modifier = Modifier + .fillMaxWidth() .padding(horizontal = 24.dp, vertical = 8.dp) ) { - // ================================================= - // NAME + EDIT - // ================================================= - + // NAME, AGE & EDIT BUTTON Row( - + modifier = Modifier.fillMaxWidth(), 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( - onClick = onEditClick, - modifier = Modifier.height(30.dp), - contentPadding = PaddingValues(horizontal = 10.dp, vertical = 0.dp), - border = ButtonDefaults - .outlinedButtonBorder - .copy(width = 1.dp) + // BIO CONTAINER + if (!profile?.bio.isNullOrBlank()) { + Card( + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(12.dp), + colors = CardDefaults.cardColors(containerColor = Color(0xFFF9F9F9)), + 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 = "Edit", - fontSize = 12.sp, - color = BrandMagenta, - fontWeight = FontWeight.Bold + text = profile.bio!!, + fontSize = 13.sp, + color = textDark, + lineHeight = 18.sp, + modifier = Modifier.padding(12.dp) ) } + Spacer(modifier = Modifier.height(10.dp)) } - Spacer(modifier = Modifier.height(4.dp)) - // ================================================= - // BIO - // ================================================= - - Log.d("my id","${profileResponse?.id}" ) - Text( - - text = profileResponse?.profile?.bio?:"", - fontSize = 13.sp, - color = TextMuted, - lineHeight = 18.sp - ) + // INTERESTS CHIPS + if (!profile?.interests.isNullOrEmpty()) { + FlowRow( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(6.dp), + verticalArrangement = Arrangement.spacedBy(6.dp) + ) { + profile.interests.forEach { interest -> + Surface( + shape = RoundedCornerShape(16.dp), + color = BrandMagenta.copy(alpha = 0.1f) + ) { + 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)) + // ==================================================== // PREMIUM BANNER // ==================================================== Box( - modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp) + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) .clip(RoundedCornerShape(16.dp)) - .background( - brush = Brush.horizontalGradient( - colors = listOf(BrandMagenta, BrandPurple) - ) - ) + .background(brush = Brush.horizontalGradient(colors = listOf(BrandMagenta, BrandPurple))) .padding(16.dp) ) { Row( @@ -241,42 +267,26 @@ fun MyProfileScreen( verticalAlignment = Alignment.CenterVertically ) { Column { - Text( text = "VibeCheck Premium", color = Color.White, fontSize = 16.sp, fontWeight = FontWeight.Bold ) - - Spacer( - modifier = Modifier.height(2.dp) - ) - + Spacer(modifier = Modifier.height(2.dp)) Text( - text = "Unlock unlimited likes & more", color = Color.White.copy(alpha = 0.8f), fontSize = 12.sp ) } - // UPGRADE BUTTON - Button( - onClick = onUpgradeClick, - colors = ButtonDefaults.buttonColors( - containerColor = Color.White - ), + colors = ButtonDefaults.buttonColors(containerColor = Color.White), shape = RoundedCornerShape(20.dp), - contentPadding = PaddingValues( - horizontal = 14.dp, - vertical = 4.dp - ) + contentPadding = PaddingValues(horizontal = 14.dp, vertical = 4.dp) ) { - Text( - text = "Upgrade", color = BrandMagenta, fontSize = 12.sp, @@ -286,155 +296,98 @@ fun MyProfileScreen( } } - - Spacer( - modifier = Modifier.height(16.dp) - ) + Spacer(modifier = Modifier.height(16.dp)) // ==================================================== - // STATISTICS + // STATISTICS CARDS // ==================================================== - Row( - - modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), horizontalArrangement = Arrangement.spacedBy(8.dp) ) { - StatCard( number = profileResponse?.liked_users_count?.toString() ?: "0", label = "Likes", modifier = Modifier.weight(1f), onClick = { 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 + putExtra("TYPE", "Likes") } context.startActivity(intent) onLikesClick() } ) - StatCard( - number = profileResponse?.liked_by_users_count?.toString() ?: "0", label = "Liked", modifier = Modifier.weight(1f), 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 + putExtra("TYPE", "Liked") } context.startActivity(intent) - onLikesClick() + onLikedClick() } ) - - -// StatCard( -// number = "Top", -// label = "Match", -// numberColor = BrandMagenta, -// modifier = Modifier.weight(1f) -// ) StatCard( number = profileResponse?.matches_count?.toString() ?: "0", label = "Matches", modifier = Modifier.weight(1f), 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 + putExtra("TYPE", "Matches") } context.startActivity(intent) - onLikesClick() + 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)) + ProfilePostsGrid(posts = profileResponse?.posts ?: emptyList()) -// ============================================================ -// 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 - - - Image( - painter = painterResource( - id = R.drawable.locationpermissionbg - ), - - contentDescription = "Profile Image $imageIndex", - modifier = Modifier.weight(1f).aspectRatio(1f).padding(1.dp), - contentScale = ContentScale.Crop - ) - } - } - } + Spacer(modifier = Modifier.height(30.dp)) } } + // ============================================================ // STAT CARD // ============================================================ - @Composable private fun StatCard( number: String, label: String, modifier: Modifier = Modifier, numberColor: Color = textDark, - onClick:()->Unit - + onClick: () -> Unit ) { - Card( modifier = modifier.clickable { onClick() }, shape = RoundedCornerShape(12.dp), - - colors = CardDefaults.cardColors( - containerColor = Color(0xFFFAFAFA) - ), - - border = - CardDefaults.outlinedCardBorder() - .copy(width = 0.5.dp) + colors = CardDefaults.cardColors(containerColor = Color(0xFFFAFAFA)), + border = CardDefaults.outlinedCardBorder().copy(width = 0.5.dp) ) { - Column( - modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 8.dp), horizontalAlignment = Alignment.CenterHorizontally ) { Text( @@ -443,10 +396,7 @@ private fun StatCard( fontWeight = FontWeight.Bold, color = numberColor ) - Spacer( - modifier = Modifier.height(2.dp) - ) - + Spacer(modifier = Modifier.height(2.dp)) Text( text = label, fontSize = 11.sp, @@ -458,39 +408,299 @@ private fun StatCard( // ============================================================ -// PREVIEW +// STAGGERED PROFILE POSTS GRID (Matches your custom Masonry layout) +// ============================================================ + +@Composable +private fun ProfilePostsGrid(posts: List) { + 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() + val col2 = mutableListOf() + + 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) @Composable fun MyProfileScreenSuccessPreview() { DattingAPPTheme { - // Mock UserResponse matching your backend model hierarchy + // Mock UserResponse matching your backend model structure val mockUserResponse = UserResponse( id = 1, - email_or_phone = "alex.dev@example.com", + email_or_phone = "elena@example.com", status = "active", profile = ProfileData( - full_name = "Alex Morgan", - gender = "Male", - birth_date = "1995-05-15", + full_name = "Elena", + gender = "Female", + birth_date = "2002-04-12", // 24 years old city = "New York", - county = "Manhattan", + county = null, country = "USA", 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", video_url = null, - interests = listOf("Hiking", "Cooking", "Photography") + interests = listOf("Photography", "Dogs", "Coffee Shop Lover", "Art Galleries") ), 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_by_users = emptyList(), matches = emptyList(), - liked_users_count = 24, - liked_by_users_count = 12, - matches_count = 8 + liked_users_count = 42, + liked_by_users_count = 128, + matches_count = 18 ) MyProfileScreen( @@ -499,4 +709,4 @@ fun MyProfileScreenSuccessPreview() { errorMessage = null ) } -} +} \ No newline at end of file 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 7aaa277..0c49f58 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 @@ -535,12 +535,12 @@ sealed interface LikedUiState { class LikedViewModel : ViewModel() { // ✅ three separate states, one per list type - private val _likesUiState = MutableStateFlow(LikedUiState.Idle) // users who liked ME - val likesUiState: StateFlow = _likesUiState.asStateFlow() - - private val _likedUiState = MutableStateFlow(LikedUiState.Idle) // users I liked + private val _likedUiState = MutableStateFlow(LikedUiState.Idle) // users who liked ME val likedUiState: StateFlow = _likedUiState.asStateFlow() + private val _likesUiState = MutableStateFlow(LikedUiState.Idle) // users I liked + val likesUiState: StateFlow = _likesUiState.asStateFlow() + private val _matchesUiState = MutableStateFlow(LikedUiState.Idle) // matches val matchesUiState: StateFlow = _matchesUiState.asStateFlow() 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 e406cb3..598983d 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,13 @@ class TokenManager private constructor(context: Context) { Context.MODE_PRIVATE ) - fun saveTokens(accessToken: String, refreshToken: String?,userId: Int,currenUserName:String?,profile_image_url:String?) { + private val prefProfile = + context.applicationContext.getSharedPreferences( + PREF_NAME, + Context.MODE_PRIVATE + ) + + fun saveTokens(accessToken: String, refreshToken: String?) { val cleanToken = accessToken.trim() .replace( Regex("^Bearer\\s+", RegexOption.IGNORE_CASE), @@ -22,6 +28,14 @@ class TokenManager private constructor(context: Context) { val saved = preferences.edit() .putString(KEY_ACCESS_TOKEN, cleanToken) .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) .putString("currenUserName", currenUserName) .putString("profile_image_url", profile_image_url) @@ -33,12 +47,13 @@ class TokenManager private constructor(context: Context) { + fun getUserId(): Int { - return preferences.getInt("user_id", -1) + return prefProfile.getInt("user_id", -1) } - fun currentUserName(): String? = preferences.getString("full_name", null) - fun currentProfileImage(): String? = preferences.getString("profile_image_url", null) + fun currentUserName(): String? = prefProfile.getString("currenUserName", null) + fun currentProfileImage(): String? = prefProfile.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/RegistrationScreen.kt b/app/src/main/java/com/example/dattingapp/registration/RegistrationScreen.kt index 9389b95..d25e3ad 100644 --- a/app/src/main/java/com/example/dattingapp/registration/RegistrationScreen.kt +++ b/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.os.Looper import android.Manifest +import android.util.Log import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Column @@ -100,6 +101,8 @@ import androidx.compose.material.icons.filled.LocationOn // Permission check import androidx.core.content.ContextCompat +import com.example.dattingapp.homes.networkandapi.TokenManager + class RegistrationScreen : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { enableEdgeToEdge() @@ -156,7 +159,12 @@ fun RegistrationFlowContainer( when (val state = uiState) { is RegistrationUiState.Success -> { 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 val intent = Intent(context, UploadProfileImageActivity::class.java).apply { putExtra("ACCESS_TOKEN", state.response.accessToken)