diff --git a/app/src/main/kotlin/com/fnregistry/citas_kt/MainActivity.kt b/app/src/main/kotlin/com/fnregistry/citas_kt/MainActivity.kt index 72e7c04..f936605 100644 --- a/app/src/main/kotlin/com/fnregistry/citas_kt/MainActivity.kt +++ b/app/src/main/kotlin/com/fnregistry/citas_kt/MainActivity.kt @@ -3,22 +3,356 @@ package com.fnregistry.citas_kt import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface -import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +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.text.style.TextAlign +import androidx.compose.ui.unit.dp +import fn.compose.theme.FnRadius +import fn.compose.theme.FnSpacing import fn.compose.theme.FnTheme +import fn.compose.ui.FnAlert +import fn.compose.ui.FnAlertVariant +import fn.compose.ui.FnAppShell +import fn.compose.ui.FnAvatar +import fn.compose.ui.FnAvatarSize +import fn.compose.ui.FnBadge +import fn.compose.ui.FnBadgeColor +import fn.compose.ui.FnButton +import fn.compose.ui.FnButtonVariant +import fn.compose.ui.FnCard +import fn.compose.ui.FnDialog +import fn.compose.ui.FnEmptyState +import fn.compose.ui.FnGroup +import fn.compose.ui.FnPageHeader +import fn.compose.ui.FnStack +import fn.compose.ui.FnTabs +import fn.compose.ui.FnText +import fn.compose.ui.FnTextSize +import fn.compose.ui.FnTitle class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { FnTheme { - Surface(modifier = Modifier.fillMaxSize()) { - Text("citas_kt ready") + Surface(modifier = Modifier.fillMaxSize()) { CitasApp() } + } + } + } +} + +data class Profile( + val name: String, + val age: Int, + val city: String, + val bio: String, + val interests: List, + val gradient: List, +) + +data class Match(val profile: Profile, val lastMessage: String, val unread: Int) + +private val PROFILES = listOf( + Profile( + "Lucia", 27, "Madrid", + "Disenadora UX. Cafe de especialidad, montana y libros de no ficcion.", + listOf("Diseno", "Senderismo", "Lectura", "Cafe"), + listOf(Color(0xFFFF6B9D), Color(0xFFC06CFF)), + ), + Profile( + "Marcos", 31, "Barcelona", + "Cocinero apasionado de la pasta fresca. Busco compania para descubrir mercados.", + listOf("Cocina", "Cine", "Viajes"), + listOf(Color(0xFF42A5F5), Color(0xFF26C6DA)), + ), + Profile( + "Sofia", 24, "Valencia", + "Estudiante de biologia marina. Surf los domingos y plantas de interior.", + listOf("Surf", "Naturaleza", "Yoga", "Plantas"), + listOf(Color(0xFF66BB6A), Color(0xFF26A69A)), + ), + Profile( + "Hugo", 29, "Bilbao", + "Ingeniero de software por el dia, musico amateur por la noche. Toco guitarra.", + listOf("Musica", "Tech", "Cervezas", "Pintxos"), + listOf(Color(0xFFFFB74D), Color(0xFFFF7043)), + ), +) + +private val MATCHES = listOf( + Match(PROFILES[0], "Que te parece quedar el sabado para tomar algo?", 2), + Match(PROFILES[2], "Jajaja eres muy gracioso, dime mas", 0), + Match(PROFILES[3], "Te paso la cancion que te decia", 1), +) + +@Composable +private fun CitasApp() { + var tab by remember { mutableStateOf(0) } + FnAppShell(title = "Latido") { padding -> + FnStack( + modifier = Modifier.padding(padding).fillMaxSize(), + gap = FnSpacing.xs, + ) { + FnTabs( + tabs = listOf("Descubrir", "Matches", "Chats", "Perfil"), + selectedIndex = tab, + onTabSelected = { tab = it }, + scrollable = false, + ) + Box( + modifier = Modifier + .padding(horizontal = FnSpacing.md, vertical = FnSpacing.sm) + .fillMaxSize(), + ) { + when (tab) { + 0 -> DiscoverTab() + 1 -> MatchesTab() + 2 -> ChatsTab() + 3 -> ProfileTab() } } } } } + +@Composable +private fun DiscoverTab() { + var index by remember { mutableStateOf(0) } + var liked by remember { mutableStateOf(null) } + var passed by remember { mutableStateOf(0) } + var likes by remember { mutableStateOf(0) } + + if (index >= PROFILES.size) { + FnEmptyState( + title = "No quedan perfiles cerca", + description = "Has visto $passed pasados y $likes likes. Vuelve manana.", + icon = "๐Ÿ’”", + action = { + FnButton(text = "Reiniciar", onClick = { + index = 0; passed = 0; likes = 0 + }) + }, + ) + return + } + + val p = PROFILES[index] + FnStack(modifier = Modifier.fillMaxSize(), gap = FnSpacing.md) { + FnCard(modifier = Modifier.fillMaxWidth(), padding = PaddingValues(0.dp)) { + FnStack(gap = FnSpacing.sm) { + Box( + modifier = Modifier + .fillMaxWidth() + .height(280.dp) + .clip(RoundedCornerShape(topStart = FnRadius.md, topEnd = FnRadius.md)) + .background(Brush.linearGradient(p.gradient)), + contentAlignment = Alignment.Center, + ) { + FnAvatar( + initials = p.name.take(2).uppercase(), + size = FnAvatarSize.Lg, + backgroundColor = Color.White.copy(alpha = 0.25f), + textColor = Color.White, + ) + } + FnStack( + modifier = Modifier.padding(horizontal = FnSpacing.md, vertical = FnSpacing.sm), + gap = FnSpacing.xs, + ) { + FnTitle(text = "${p.name}, ${p.age}", order = 2) + FnText(text = "๐Ÿ“ ${p.city}", size = FnTextSize.Sm) + FnText(text = p.bio, size = FnTextSize.Sm) + FnGroup(gap = FnSpacing.xs) { + p.interests.forEach { tag -> + FnBadge(text = tag, color = FnBadgeColor.Brand) + } + } + } + } + } + + FnGroup( + modifier = Modifier.fillMaxWidth(), + arrangement = Arrangement.SpaceEvenly, + ) { + FnButton( + text = "โœ• Pasar", + onClick = { passed++; index++ }, + variant = FnButtonVariant.Outlined, + ) + FnButton( + text = "โญ Super", + onClick = { liked = p; likes++; index++ }, + variant = FnButtonVariant.Secondary, + ) + FnButton( + text = "โ™ฅ Like", + onClick = { liked = p; likes++; index++ }, + variant = FnButtonVariant.Filled, + ) + } + + FnText( + text = "${likes} likes ยท ${passed} pasados", + size = FnTextSize.Xs, + align = TextAlign.Center, + modifier = Modifier.fillMaxWidth(), + ) + } + + FnDialog( + open = liked != null, + onDismiss = { liked = null }, + title = "Es un match!", + description = "A ${liked?.name} tambien le gustas. Escribele ya.", + confirmText = "Enviar mensaje", + cancelText = "Seguir viendo", + onConfirm = { liked = null }, + ) +} + +@Composable +private fun MatchesTab() { + FnStack( + modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()), + gap = FnSpacing.md, + ) { + FnPageHeader(title = "Tus matches", subtitle = "${MATCHES.size} personas conectadas") + MATCHES.forEach { m -> + FnCard(modifier = Modifier.fillMaxWidth()) { + FnGroup(modifier = Modifier.fillMaxWidth(), gap = FnSpacing.md) { + FnAvatar( + initials = m.profile.name.take(2).uppercase(), + size = FnAvatarSize.Md, + backgroundColor = m.profile.gradient.first(), + textColor = Color.White, + ) + FnStack(modifier = Modifier.weight(1f), gap = 4.dp) { + FnText(text = "${m.profile.name}, ${m.profile.age}", size = FnTextSize.Md) + FnText(text = m.profile.city, size = FnTextSize.Xs) + } + if (m.unread > 0) { + FnBadge(text = "${m.unread}", color = FnBadgeColor.Brand) + } + } + } + } + } +} + +@Composable +private fun ChatsTab() { + FnStack( + modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()), + gap = FnSpacing.md, + ) { + FnPageHeader(title = "Mensajes", subtitle = "Conversaciones activas") + if (MATCHES.isEmpty()) { + FnEmptyState( + title = "Sin mensajes todavia", + description = "Cuando alguien te de like apareceran aqui.", + icon = "๐Ÿ’ฌ", + ) + return@FnStack + } + MATCHES.forEach { m -> + FnCard(modifier = Modifier.fillMaxWidth()) { + FnGroup(modifier = Modifier.fillMaxWidth(), gap = FnSpacing.md) { + FnAvatar( + initials = m.profile.name.take(2).uppercase(), + size = FnAvatarSize.Md, + backgroundColor = m.profile.gradient.first(), + textColor = Color.White, + ) + FnStack(modifier = Modifier.weight(1f), gap = 4.dp) { + FnGroup(modifier = Modifier.fillMaxWidth(), gap = FnSpacing.xs) { + FnText(text = m.profile.name, size = FnTextSize.Md, modifier = Modifier.weight(1f)) + if (m.unread > 0) FnBadge(text = "${m.unread}", color = FnBadgeColor.Brand) + } + FnText(text = m.lastMessage, size = FnTextSize.Sm) + } + } + } + } + } +} + +@Composable +private fun ProfileTab() { + FnStack( + modifier = Modifier.fillMaxSize().verticalScroll(rememberScrollState()), + gap = FnSpacing.md, + ) { + FnCard(modifier = Modifier.fillMaxWidth()) { + FnStack( + modifier = Modifier.fillMaxWidth(), + gap = FnSpacing.sm, + align = Alignment.CenterHorizontally, + ) { + FnAvatar( + initials = "YO", + size = FnAvatarSize.Lg, + backgroundColor = Color(0xFFEC407A), + textColor = Color.White, + ) + FnTitle(text = "Tu, 28", order = 2) + FnText(text = "Madrid ยท Premium", size = FnTextSize.Sm) + FnGroup(gap = FnSpacing.xs) { + FnBadge(text = "Verificado", color = FnBadgeColor.Green) + FnBadge(text = "Premium", color = FnBadgeColor.Brand) + } + } + } + FnAlert( + title = "Completa tu perfil", + message = "Anade 2 fotos mas y duplica tus matches.", + variant = FnAlertVariant.Info, + ) + FnCard(modifier = Modifier.fillMaxWidth()) { + FnStack(gap = FnSpacing.sm) { + FnTitle(text = "Estadisticas", order = 3) + FnGroup(modifier = Modifier.fillMaxWidth(), arrangement = Arrangement.SpaceBetween) { + Stat("Likes dados", "47") + Stat("Matches", "${MATCHES.size}") + Stat("Vistas", "128") + } + } + } + FnButton( + text = "Cerrar sesion", + onClick = {}, + variant = FnButtonVariant.Outlined, + modifier = Modifier.fillMaxWidth(), + ) + } +} + +@Composable +private fun Stat(label: String, value: String) { + FnStack(gap = 4.dp, align = Alignment.CenterHorizontally) { + FnTitle(text = value, order = 3, color = MaterialTheme.colorScheme.primary) + FnText(text = label, size = FnTextSize.Xs) + } +}