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

480 lines
16 KiB

package com.example.dattingapp.homes
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.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.outlined.Edit
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import coil.compose.AsyncImage
import com.example.dattingapp.R
import com.example.dattingapp.homes.profile.UserResponse
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 androidx.compose.foundation.clickable
import androidx.compose.ui.platform.LocalContext
import androidx.core.content.ContextCompat.startActivity
// ============================================================
// MY PROFILE SCREEN
// ============================================================
@Composable
fun MyProfileScreen(
profileResponse : UserResponse?, // Change from MyProfileData? to MyProfileResponse?
isLoading: Boolean,
errorMessage: String?,
onRetry: () -> Unit = {},
onEditClick: () -> Unit = {},
onUpgradeClick: () -> Unit = {},
onSettingsClick: () -> Unit = {},
onLikesClick: () -> Unit={},
onLikedClick: () -> Unit={},
onMatchClick: () -> Unit={}
) {
// ========================================================
// FULL SCREEN SCROLL
// ========================================================
val context = LocalContext.current
val scrollState = rememberScrollState()
Column(
modifier = Modifier.fillMaxSize().background(Color.White).verticalScroll(scrollState)) {
// ====================================================
// HEADER
// ====================================================
Box(
modifier = Modifier.fillMaxWidth().height(260.dp)
) {
// =================================================
// COVER IMAGE
// =================================================
Image(
painter = painterResource(id = R.drawable.locationpermissionbg),
contentDescription = "Cover Banner",
modifier = Modifier.fillMaxWidth().height(200.dp),
contentScale = ContentScale.Crop
)
// =================================================
// SETTINGS BUTTON
// =================================================
IconButton(
onClick = onSettingsClick,
modifier = Modifier.align(Alignment.TopEnd)
.padding(top = 16.dp, end = 16.dp)
.size(36.dp)
.clip(CircleShape)
.background(Color.Black.copy(alpha = 0.3f)
)
) {
Icon(
imageVector = Icons.Outlined.Settings,
contentDescription = "Settings",
tint = Color.White,
modifier = Modifier.size(20.dp)
)
}
// =================================================
// PROFILE IMAGE
// =================================================
Box(
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,
contentDescription = "Profile Picture",
contentScale = ContentScale.Crop,
placeholder = painterResource(id = R.drawable.locationpermissionbg),
error = painterResource(id = R.drawable.locationpermissionbg),
modifier = Modifier
.fillMaxSize()
.clip(CircleShape)
.border(width = 4.dp, color = Color.White, shape = CircleShape)
)
// =================================================
// VERIFIED BADGE
// =================================================
Box(
modifier = Modifier.align(Alignment.BottomEnd).size(28.dp).clip(CircleShape)
.background(BrandMagenta)
.border(width = 2.dp, color = Color.White, shape = CircleShape
),
contentAlignment = Alignment.Center
) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = "Verified",
tint = Color.White,
modifier = Modifier.size(16.dp)
)
}
}
}
// ====================================================
// USER INFORMATION
// ====================================================
Column(
modifier = Modifier.fillMaxWidth()
.padding(horizontal = 24.dp, vertical = 8.dp)
) {
// =================================================
// NAME + EDIT
// =================================================
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
text = profileResponse?.profile?.full_name?:"",
fontSize = 22.sp,
fontWeight = FontWeight.Bold,
color = BrandMagenta
)
// EDIT BUTTON
OutlinedButton(
onClick = onEditClick,
modifier = Modifier.height(30.dp),
contentPadding = PaddingValues(horizontal = 10.dp, vertical = 0.dp),
border = ButtonDefaults
.outlinedButtonBorder
.copy(width = 1.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
)
}
}
Spacer(modifier = Modifier.height(4.dp))
// =================================================
// BIO
// =================================================
Text(
text = profileResponse?.profile?.bio?:"",
fontSize = 13.sp,
color = TextMuted,
lineHeight = 18.sp
)
}
Spacer(modifier = Modifier.height(12.dp))
// ====================================================
// PREMIUM BANNER
// ====================================================
Box(
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp)
.clip(RoundedCornerShape(16.dp))
.background(
brush = Brush.horizontalGradient(
colors = listOf(BrandMagenta, BrandPurple)
)
)
.padding(16.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column {
Text(
text = "VibeCheck Premium",
color = Color.White,
fontSize = 16.sp,
fontWeight = FontWeight.Bold
)
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
),
shape = RoundedCornerShape(20.dp),
contentPadding = PaddingValues(
horizontal = 14.dp,
vertical = 4.dp
)
) {
Text(
text = "Upgrade",
color = BrandMagenta,
fontSize = 12.sp,
fontWeight = FontWeight.Bold
)
}
}
}
Spacer(
modifier = Modifier.height(16.dp)
)
// ====================================================
// STATISTICS
// ====================================================
Row(
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)
context.startActivity(intent)
onLikesClick()
}
)
StatCard(
number = profileResponse?.liked_by_users_count?.toString() ?: "0",
label = "Liked",
modifier = Modifier.weight(1f),
onClick = { /* Optional: Handle Matches click */ }
)
// 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 = { /* Optional: Handle Matches click */ }
)
}
Spacer(
modifier = Modifier.height(16.dp)
)
ProfileMediaGrid()
Spacer(
modifier = Modifier.height(30.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
Image(
painter = painterResource(
id = R.drawable.locationpermissionbg
),
contentDescription = "Profile Image $imageIndex",
modifier = Modifier.weight(1f).aspectRatio(1f).padding(1.dp),
contentScale = ContentScale.Crop
)
}
}
}
}
}
// ============================================================
// STAT CARD
// ============================================================
@Composable
private fun StatCard(
number: String,
label: String,
modifier: Modifier = Modifier,
numberColor: Color = textDark,
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)
) {
Column(
modifier = Modifier.fillMaxWidth().padding(vertical = 12.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = number,
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
color = numberColor
)
Spacer(
modifier = Modifier.height(2.dp)
)
Text(
text = label,
fontSize = 11.sp,
color = TextMuted
)
}
}
}
// ============================================================
// PREVIEW
// ============================================================
@Preview(showBackground = true, showSystemUi = true)
@Composable
fun MyProfileScreenSuccessPreview() {
DattingAPPTheme {
// Mock UserResponse matching your backend model hierarchy
val mockUserResponse = UserResponse(
id = 1,
email_or_phone = "alex.dev@example.com",
status = "active",
profile = ProfileData(
full_name = "Alex Morgan",
gender = "Male",
birth_date = "1995-05-15",
city = "New York",
county = "Manhattan",
country = "USA",
relationship_goal = "Long-term partnership",
bio = "Adventure seeker, dog lover, and amateur chef. Let's find a vibe!",
profile_image_url = "https://picsum.photos/300/300",
video_url = null,
interests = listOf("Hiking", "Cooking", "Photography")
),
created_at = "2026-01-01",
posts = emptyList(),
liked_users = emptyList(),
liked_by_users = emptyList(),
matches = emptyList(),
liked_users_count = 24,
liked_by_users_count = 12,
matches_count = 8
)
MyProfileScreen(
profileResponse = mockUserResponse,
isLoading = false,
errorMessage = null
)
}
}