diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 18d8d0c..b5ac541 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -11,6 +11,7 @@
+
-
-
-
-
-
-
-
+ LazyColumn(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(Color(0xFFFAFAFA)),
+ contentPadding = PaddingValues(
+ top = innerPadding.calculateTopPadding(),
+ bottom = innerPadding.calculateBottomPadding() + 16.dp
+ )
+ ) {
+ // Search Bar
+ item {
+ OutlinedTextField(
+ value = "",
+ onValueChange = {},
+ placeholder = { Text("Search chats or matches...", fontSize = 14.sp) },
+ leadingIcon = {
+ Icon(
+ Icons.Default.Search,
+ contentDescription = null,
+ tint = Color.Gray
+ )
+ },
+ trailingIcon = {
+ Icon(
+ Icons.Default.Mic,
+ contentDescription = null,
+ tint = Color.Gray
+ )
+ },
+ shape = RoundedCornerShape(24.dp),
+ colors = OutlinedTextFieldDefaults.colors(
+ focusedBorderColor = Color(0xFFFFCDD2),
+ unfocusedBorderColor = Color(0xFFFFCDD2),
+ focusedContainerColor = Color.White,
+ unfocusedContainerColor = Color.White
+ ),
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 16.dp, vertical = 8.dp)
+ )
+ }
+
+ // Active Sparks & Vibes Row
+ item {
+ Column(modifier = Modifier.padding(vertical = 8.dp)) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 16.dp),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ "Active Sparks & Vibes",
+ fontWeight = FontWeight.Bold,
+ fontSize = 14.sp
+ )
+ Text(
+ "View all",
+ color = Color(0xFFE91E63),
+ fontSize = 12.sp,
+ fontWeight = FontWeight.SemiBold
+ )
+ }
+
+ Spacer(modifier = Modifier.height(8.dp))
+
+ LazyRow(
+ contentPadding = PaddingValues(horizontal = 16.dp),
+ horizontalArrangement = Arrangement.spacedBy(12.dp)
+ ) {
+ items(sampleSparks) { spark ->
+ ActiveSparkItem(spark = spark)
+ }
+ }
+ }
+ }
+
+ // Filter Chips
+ item {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 16.dp, vertical = 8.dp),
+ horizontalArrangement = Arrangement.spacedBy(8.dp)
+ ) {
+ Button(
+ onClick = {},
+ colors = ButtonDefaults.buttonColors(containerColor = Color(0xFF9C27B0)),
+ contentPadding = PaddingValues(horizontal = 16.dp, vertical = 6.dp),
+ modifier = Modifier.height(32.dp)
+ ) {
+ Text("All", fontSize = 12.sp)
+ }
+
+ OutlinedButton(
+ onClick = {},
+ border = BorderStroke(1.dp, Color(0xFFFFCDD2)),
+ contentPadding = PaddingValues(horizontal = 12.dp, vertical = 6.dp),
+ modifier = Modifier.height(32.dp)
+ ) {
+ Text("Unread", color = Color.Black, fontSize = 12.sp)
+ Spacer(modifier = Modifier.width(4.dp))
+ Text(
+ "3",
+ color = Color(0xFFE91E63),
+ fontSize = 11.sp,
+ fontWeight = FontWeight.Bold
+ )
+ }
+
+ OutlinedButton(
+ onClick = {},
+ border = BorderStroke(1.dp, Color(0xFFFFCDD2)),
+ contentPadding = PaddingValues(horizontal = 12.dp, vertical = 6.dp),
+ modifier = Modifier.height(32.dp)
+ ) {
+ Text("Matches", color = Color.Black, fontSize = 12.sp)
+ }
+
+ OutlinedButton(
+ onClick = {},
+ border = BorderStroke(1.dp, Color(0xFFFFCDD2)),
+ contentPadding = PaddingValues(horizontal = 12.dp, vertical = 6.dp),
+ modifier = Modifier.height(32.dp)
+ ) {
+ Icon(
+ imageVector = Icons.Default.FlashOn,
+ contentDescription = null,
+ tint = Color(0xFFE91E63),
+ modifier = Modifier.size(14.dp)
+ )
+ Spacer(modifier = Modifier.width(2.dp))
+ Text("Vibes", color = Color.Black, fontSize = 12.sp)
+ }
+ }
+ }
+
+ // Chat List Items
+ items(sampleChats) { chat ->
+ ChatItemCard(chat = chat)
}
}
}
}
+@Composable
+fun ActiveSparkItem(spark: ActiveSpark) {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.spacedBy(4.dp)
+ ) {
+ Box(contentAlignment = Alignment.BottomEnd) {
+ Box(
+ modifier = Modifier
+ .size(56.dp)
+ .clip(CircleShape)
+ .background(Color(0xFFCE93D8))
+ .border(
+ width = 2.dp,
+ color = if (spark.isUser) Color.Transparent else Color(0xFFE91E63),
+ shape = CircleShape
+ )
+ )
+
+ if (spark.isUser) {
+ Box(
+ modifier = Modifier
+ .size(18.dp)
+ .background(Color(0xFFE91E63), CircleShape)
+ .border(1.5.dp, Color.White, CircleShape),
+ contentAlignment = Alignment.Center
+ ) {
+ Icon(
+ imageVector = Icons.Default.Add,
+ contentDescription = "Add",
+ tint = Color.White,
+ modifier = Modifier.size(12.dp)
+ )
+ }
+ } else {
+ Box(
+ modifier = Modifier
+ .size(12.dp)
+ .background(Color(0xFF4CAF50), CircleShape)
+ .border(1.5.dp, Color.White, CircleShape)
+ )
+ }
+ }
+ Text(
+ text = spark.name,
+ fontSize = 11.sp,
+ fontWeight = FontWeight.Medium
+ )
+ }
+}
+
+@Composable
+fun ChatItemCard(chat: ChatMessage) {
+ Card(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 16.dp, vertical = 4.dp),
+ shape = RoundedCornerShape(16.dp),
+ colors = CardDefaults.cardColors(containerColor = Color.White),
+ border = BorderStroke(1.dp, Color(0xFFFFEBEE))
+ ) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(12.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ // Profile Avatar Box
+ Box(modifier = Modifier.size(52.dp)) {
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .clip(RoundedCornerShape(12.dp))
+ .background(Color(0xFFBA68C8))
+ )
+
+ if (chat.matchPercentage != null) {
+ Surface(
+ color = Color(0xFF9C27B0),
+ shape = RoundedCornerShape(8.dp),
+ modifier = Modifier.align(Alignment.BottomStart)
+ ) {
+ Text(
+ text = "${chat.matchPercentage}%",
+ color = Color.White,
+ fontSize = 8.sp,
+ fontWeight = FontWeight.Bold,
+ modifier = Modifier.padding(horizontal = 4.dp, vertical = 1.dp)
+ )
+ }
+ }
+
+ if (chat.isOnline) {
+ Box(
+ modifier = Modifier
+ .size(10.dp)
+ .background(Color(0xFF4CAF50), CircleShape)
+ .border(1.dp, Color.White, CircleShape)
+ .align(Alignment.BottomEnd)
+ )
+ }
+
+ if (chat.isAiBot) {
+ Box(
+ modifier = Modifier
+ .size(16.dp)
+ .background(Color(0xFF9C27B0), CircleShape)
+ .align(Alignment.TopEnd),
+ contentAlignment = Alignment.Center
+ ) {
+ Icon(
+ imageVector = Icons.Default.AutoAwesome,
+ contentDescription = null,
+ tint = Color.White,
+ modifier = Modifier.size(10.dp)
+ )
+ }
+ }
+ }
+
+ Spacer(modifier = Modifier.width(12.dp))
+
+ // Details Section
+ Column(
+ modifier = Modifier.weight(1f),
+ verticalArrangement = Arrangement.spacedBy(4.dp)
+ ) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(4.dp)
+ ) {
+ Text(
+ text = if (chat.age > 0) "${chat.name}, ${chat.age}" else chat.name,
+ fontWeight = FontWeight.Bold,
+ fontSize = 15.sp
+ )
+ if (chat.isVerified) {
+ Icon(
+ imageVector = Icons.Default.CheckCircle,
+ contentDescription = "Verified",
+ tint = Color(0xFFE91E63),
+ modifier = Modifier.size(14.dp)
+ )
+ }
+ if (chat.aiTag != null) {
+ Surface(
+ color = Color(0xFFFFEBEE),
+ shape = RoundedCornerShape(4.dp)
+ ) {
+ Text(
+ text = chat.aiTag,
+ color = Color(0xFFE91E63),
+ fontSize = 9.sp,
+ fontWeight = FontWeight.Bold,
+ modifier = Modifier.padding(horizontal = 4.dp, vertical = 1.dp)
+ )
+ }
+ }
+ }
+
+ // Message Content
+ when {
+ chat.messageText != null -> {
+ Text(
+ text = chat.messageText,
+ fontSize = 12.sp,
+ color = Color.Gray,
+ maxLines = 1
+ )
+ }
+ chat.isVoiceNote -> {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(4.dp)
+ ) {
+ Icon(
+ imageVector = Icons.Default.Mic,
+ contentDescription = null,
+ tint = Color(0xFFE91E63),
+ modifier = Modifier.size(14.dp)
+ )
+ Surface(
+ color = Color(0xFFFFEBEE),
+ shape = RoundedCornerShape(8.dp)
+ ) {
+ Text(
+ text = "|||!|!|| ${chat.voiceDuration}",
+ color = Color(0xFFE91E63),
+ fontSize = 10.sp,
+ modifier = Modifier.padding(horizontal = 6.dp, vertical = 2.dp)
+ )
+ }
+ Text(
+ text = "Voice note",
+ fontSize = 12.sp,
+ fontWeight = FontWeight.SemiBold
+ )
+ }
+ }
+ chat.isPhoto -> {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(4.dp)
+ ) {
+ Icon(
+ imageVector = Icons.Default.CameraAlt,
+ contentDescription = null,
+ tint = Color(0xFFE91E63),
+ modifier = Modifier.size(14.dp)
+ )
+ Text(
+ text = chat.photoText ?: "Photo",
+ fontSize = 12.sp,
+ color = Color.Gray
+ )
+ }
+ }
+ }
+ }
+
+ // Time & Status Section
+ Column(
+ horizontalAlignment = Alignment.End,
+ verticalArrangement = Arrangement.spacedBy(4.dp)
+ ) {
+ Text(
+ text = chat.time,
+ fontSize = 11.sp,
+ color = if (chat.unreadCount > 0) Color(0xFFE91E63) else Color.Gray
+ )
+
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(4.dp)
+ ) {
+ if (chat.isPinned) {
+ Icon(
+ imageVector = Icons.Default.PushPin,
+ contentDescription = "Pinned",
+ tint = Color(0xFFE91E63),
+ modifier = Modifier.size(12.dp)
+ )
+ }
+
+ if (chat.unreadCount > 0) {
+ Box(
+ modifier = Modifier
+ .size(18.dp)
+ .background(Color(0xFF9C27B0), CircleShape),
+ contentAlignment = Alignment.Center
+ ) {
+ Text(
+ text = chat.unreadCount.toString(),
+ color = Color.White,
+ fontSize = 10.sp,
+ fontWeight = FontWeight.Bold
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// Sample Data
+val sampleSparks = listOf(
+ ActiveSpark("Your Note", isUser = true),
+ ActiveSpark("Elena"),
+ ActiveSpark("Sarah"),
+ ActiveSpark("Jordan"),
+ ActiveSpark("Marcus")
+)
+
+val sampleChats = listOf(
+ ChatMessage(
+ id = 1,
+ name = "Elena",
+ age = 24,
+ time = "12:45 PM",
+ isVerified = true,
+ matchPercentage = 98,
+ messageText = "Are you free for that coffee in ...",
+ unreadCount = 2,
+ isPinned = true,
+ isOnline = true
+ ),
+ ChatMessage(
+ id = 2,
+ name = "Sarah",
+ age = 26,
+ time = "11:30 AM",
+ isVoiceNote = true,
+ voiceDuration = "0:24",
+ unreadCount = 1,
+ isOnline = true
+ ),
+ ChatMessage(
+ id = 3,
+ name = "Jordan",
+ age = 27,
+ time = "Yesterday",
+ isPhoto = true,
+ photoText = "Photo: Check out this spot!"
+ ),
+ ChatMessage(
+ id = 4,
+ name = "VibeBot Wingmate",
+ age = 0,
+ time = "Yesterday",
+ isAiBot = true,
+ aiTag = "AI",
+ messageText = "Elena liked your coffe..."
+ ),
+ ChatMessage(
+ id = 5,
+ name = "Marcus",
+ age = 28,
+ time = "Wednesday",
+ messageText = "Haha sounds like a plan, let me kn..."
+ )
+)
+
+@Preview(showBackground = true, showSystemUi = true)
+@Composable
+fun ChatScreenPreview() {
+ MaterialTheme {
+ ChatScreen()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/dattingapp/LikeAndMatchScreen.kt b/app/src/main/java/com/example/dattingapp/LikeAndMatchScreen.kt
new file mode 100644
index 0000000..d614a48
--- /dev/null
+++ b/app/src/main/java/com/example/dattingapp/LikeAndMatchScreen.kt
@@ -0,0 +1,252 @@
+package com.example.dattingapp
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.lazy.grid.GridCells
+import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
+import androidx.compose.foundation.lazy.grid.items
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Close
+import androidx.compose.material.icons.filled.Favorite
+import androidx.compose.material.icons.filled.LocationOn
+import androidx.compose.material.icons.outlined.ChatBubbleOutline
+import androidx.compose.material3.*
+import androidx.compose.runtime.Composable
+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.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
+
+
+
+class LikeAndMatchScreen {
+}
+
+data class Profile(
+ val name: String,
+ val age: Int,
+ val distance: String,
+ val matchPercentage: Int,
+ val tags: List,
+ val imageUrl: String,
+ val hasUnread: Boolean = false
+)
+
+@Composable
+fun ProfileGrid(profiles: List, modifier: Modifier = Modifier) {
+ LazyVerticalGrid(
+ columns = GridCells.Fixed(2),
+ contentPadding = PaddingValues(12.dp),
+ horizontalArrangement = Arrangement.spacedBy(12.dp),
+ verticalArrangement = Arrangement.spacedBy(12.dp),
+ modifier = modifier.fillMaxSize()
+ ) {
+ items(profiles) { profile ->
+ ProfileCard(profile = profile)
+ }
+ }
+}
+
+@Composable
+fun ProfileCard(profile: Profile, modifier: Modifier = Modifier) {
+ Card(
+ shape = RoundedCornerShape(16.dp),
+ colors = CardDefaults.cardColors(containerColor = Color.White),
+ elevation = CardDefaults.cardElevation(defaultElevation = 2.dp),
+ modifier = modifier.fillMaxWidth()
+ ) {
+ Column(
+ modifier = Modifier.padding(8.dp),
+ verticalArrangement = Arrangement.spacedBy(8.dp)
+ ) {
+ // Image with Overlays
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .height(180.dp)
+ .clip(RoundedCornerShape(12.dp))
+ ) {
+ AsyncImage(
+ model = profile.imageUrl,
+ contentDescription = profile.name,
+ contentScale = ContentScale.Crop,
+ modifier = Modifier.fillMaxSize()
+ )
+
+ // Gradient Overlay for Text Readability
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(
+ Brush.verticalGradient(
+ colors = listOf(Color.Transparent, Color.Black.copy(alpha = 0.7f)),
+ startY = 100f
+ )
+ )
+ )
+
+ // Match Badge
+ Surface(
+ shape = RoundedCornerShape(20.dp),
+ color = Color.White.copy(alpha = 0.9f),
+ modifier = Modifier
+ .padding(8.dp)
+ .align(Alignment.TopStart)
+ ) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(4.dp),
+ modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)
+ ) {
+ Icon(
+ imageVector = Icons.Default.Favorite,
+ contentDescription = null,
+ tint = Color(0xFF6C5CE7),
+ modifier = Modifier.size(12.dp)
+ )
+ Text(
+ text = "${profile.matchPercentage}%",
+ fontSize = 11.sp,
+ fontWeight = FontWeight.Bold,
+ color = Color(0xFF2D3436)
+ )
+ }
+ }
+
+ // Notification Dot
+ if (profile.hasUnread) {
+ Box(
+ modifier = Modifier
+ .padding(8.dp)
+ .size(8.dp)
+ .clip(CircleShape)
+ .background(Color(0xFF6C5CE7))
+ .align(Alignment.TopEnd)
+ )
+ }
+
+ // Name, Age & Distance
+ Column(
+ modifier = Modifier
+ .align(Alignment.BottomStart)
+ .padding(8.dp)
+ ) {
+ Text(
+ text = "${profile.name}, ${profile.age}",
+ color = Color.White,
+ fontWeight = FontWeight.Bold,
+ fontSize = 14.sp
+ )
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(2.dp)
+ ) {
+ Icon(
+ imageVector = Icons.Default.LocationOn,
+ contentDescription = null,
+ tint = Color.White.copy(alpha = 0.8f),
+ modifier = Modifier.size(10.dp)
+ )
+ Text(
+ text = profile.distance,
+ color = Color.White.copy(alpha = 0.8f),
+ fontSize = 10.sp
+ )
+ }
+ }
+ }
+
+ // Tags Row
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(4.dp),
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ profile.tags.take(2).forEach { tag ->
+ Surface(
+ shape = RoundedCornerShape(6.dp),
+ color = Color(0xFFF1F2F6),
+ modifier = Modifier.weight(1f)
+ ) {
+ Text(
+ text = tag,
+ fontSize = 10.sp,
+ color = Color(0xFF636E72),
+ modifier = Modifier.padding(vertical = 4.dp, horizontal = 4.dp),
+ maxLines = 1
+ )
+ }
+ }
+ }
+
+ // Action Buttons
+ Row(
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier.fillMaxWidth().padding(10.dp)
+ ) {
+ IconButton(
+ onClick = { },
+ modifier = Modifier
+ .size(22.dp)
+ .background(Color(0xFFF8F9FA), CircleShape)
+ ) {
+ Icon(
+ imageVector = Icons.Default.Close,
+ contentDescription = "Pass",
+ tint = Color(0xFF636E72),
+ modifier = Modifier.size(16.dp)
+ )
+ }
+
+ IconButton(
+ onClick = { },
+ modifier = Modifier
+ .size(22.dp)
+ .background(Color(0xFFF1EFFE), CircleShape)
+ ) {
+ Icon(
+ imageVector = Icons.Outlined.ChatBubbleOutline,
+ contentDescription = "Message",
+ tint = Color(0xFF6C5CE7),
+ modifier = Modifier.size(16.dp)
+ )
+ }
+
+ IconButton(
+ onClick = { },
+ modifier = Modifier
+ .size(22.dp)
+ .background(Color(0xFFD63031), CircleShape)
+ ) {
+ Icon(
+ imageVector = Icons.Default.Favorite,
+ contentDescription = "Like",
+ tint = Color.White,
+ modifier = Modifier.size(16.dp)
+ )
+ }
+ }
+ }
+ }
+}
+
+@Preview(showBackground = true)
+@Composable
+fun ProfileGridPreview() {
+ val sampleProfiles = listOf(
+ Profile("Elena", 24, "2 miles away", 98, listOf("Photography", "Coffee"), "", true),
+ Profile("Sarah", 26, "4 miles away", 94, listOf("Travel", "Music"), ""),
+ Profile("Julian", 27, "3 miles away", 91, listOf("Music Prod", "Vinyl"), ""),
+ Profile("Maya", 25, "5 miles away", 89, listOf("Surfing", "Yoga"), "")
+ )
+
+ ProfileGrid(profiles = sampleProfiles)
+}
\ No newline at end of file
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 af091d0..0a25635 100644
--- a/app/src/main/java/com/example/dattingapp/Login/LoginActivity.kt
+++ b/app/src/main/java/com/example/dattingapp/Login/LoginActivity.kt
@@ -36,6 +36,7 @@ import androidx.compose.ui.unit.sp
import com.example.dattingapp.homes.HomeActivity
import com.example.dattingapp.R
import com.example.dattingapp.homes.networkandapi.TokenManager
+import com.example.dattingapp.permission.PermissionHelper
import com.example.dattingapp.registration.LoginRequest
import com.example.dattingapp.registration.NetworkModule
import com.example.dattingapp.registration.RegistrationScreen
@@ -44,9 +45,17 @@ import kotlinx.coroutines.launch
class LoginActivity : ComponentActivity() {
+
+ private lateinit var permissionHelper: PermissionHelper
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ permissionHelper = PermissionHelper(this)
+
+ // 2. Call Notification Permission
+ permissionHelper.requestPermissions(PermissionHelper.PermissionType.NOTIFICATION) { isGranted ->
+ if (isGranted) { /* Handle granted */ }
+ }
enableEdgeToEdge()
setContent {
DattingAPPTheme {
@@ -66,7 +75,6 @@ class LoginActivity : ComponentActivity() {
}
}
}
-
@Composable
fun LoginScreenContent(
onLoginSuccess: () -> Unit = {},
diff --git a/app/src/main/java/com/example/dattingapp/MainActivity.kt b/app/src/main/java/com/example/dattingapp/MainActivity.kt
index 68d44b3..59698c1 100644
--- a/app/src/main/java/com/example/dattingapp/MainActivity.kt
+++ b/app/src/main/java/com/example/dattingapp/MainActivity.kt
@@ -2,35 +2,49 @@ package com.example.dattingapp
import android.content.Intent
import android.os.Bundle
+import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
+import com.example.dattingapp.Login.LoginActivity
import com.example.dattingapp.homes.HomeActivity
import com.example.dattingapp.homes.networkandapi.TokenManager
-import com.example.dattingapp.permission.NotificationPermission
+import com.example.dattingapp.permission.PermissionHelper
import com.example.dattingapp.ui.theme.DattingAPPTheme
class MainActivity : ComponentActivity() {
- override fun onCreate(savedInstanceState: Bundle?) {
+ // 1. Declare PermissionHelper at class level
+ private lateinit var permissionHelper: PermissionHelper
+ override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
+
+ // 2. Initialize PermissionHelper in onCreate() BEFORE setContent
+ permissionHelper = PermissionHelper(this)
+
+ val tokenManager = TokenManager.getInstance(this)
+
+ if (tokenManager.isLoggedIn()) {
+ // User is logged in -> Navigate directly to Home and finish
+ startActivity(Intent(this, HomeActivity::class.java))
+ finish()
+ return
+ }else{
+
+ startActivity(Intent(this, LoginActivity::class.java))
+ finish()
+ }
+
+
+
setContent {
DattingAPPTheme {
- val tokenManager = TokenManager.getInstance(this)
-
- if (tokenManager.isLoggedIn()) {
- // 1. User is logged in -> Navigate directly to Home
- startActivity(Intent(this, HomeActivity::class.java))
- } else {
- // 2. User is NOT logged in -> Navigate to Notification Permission or Login
- startActivity(Intent(this, NotificationPermission::class.java))
- }
-
- // Close MainActivity so it doesn't stay on the backstack
- finish()
+ // Render your main login/welcome UI screen here instead of finishing immediately
}
}
}
-}
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/dattingapp/chat/PersonChatScreen.kt b/app/src/main/java/com/example/dattingapp/chat/PersonChatScreen.kt
new file mode 100644
index 0000000..67f7690
--- /dev/null
+++ b/app/src/main/java/com/example/dattingapp/chat/PersonChatScreen.kt
@@ -0,0 +1,385 @@
+package com.example.dattingapp.chat
+
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.shape.CircleShape
+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.automirrored.filled.Send
+import androidx.compose.material.icons.filled.Add
+import androidx.compose.material.icons.filled.PlayArrow
+import androidx.compose.material.icons.outlined.SentimentSatisfied
+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.text.style.TextAlign
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.example.dattingapp.ui.theme.AppBackground
+import com.example.dattingapp.ui.theme.HeaderTitleColor
+import com.example.dattingapp.ui.theme.InputFieldBg
+import com.example.dattingapp.ui.theme.RecipientBubbleBg
+import com.example.dattingapp.ui.theme.SenderBubbleBg
+import com.example.dattingapp.ui.theme.SubtextColor
+
+
+class PersonChatScreen {
+}
+
+
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun ChatDetailScreen(
+ userName: String = "Sarah",
+ onBackClick: () -> Unit = {}
+) {
+ var textValue by remember { mutableStateOf("") }
+
+ Scaffold(
+ topBar = {
+ TopAppBar(
+ title = {
+ Box(
+ modifier = Modifier.fillMaxWidth(),
+ contentAlignment = Alignment.Center
+ ) {
+ Text(
+ text = userName,
+ fontSize = 18.sp,
+ fontWeight = FontWeight.Bold,
+ color = HeaderTitleColor
+ )
+ }
+ },
+ navigationIcon = {
+ IconButton(onClick = onBackClick) {
+ Icon(
+ imageVector = Icons.AutoMirrored.Filled.ArrowBack,
+ contentDescription = "Back",
+ tint = Color.DarkGray
+ )
+ }
+ },
+ actions = {
+ Box(
+ modifier = Modifier
+ .padding(end = 16.dp)
+ .size(32.dp)
+ .clip(CircleShape)
+ .background(Color.LightGray)
+ ) {
+ // Replace drawable resource with profile image
+ Image(
+ painter = painterResource(id = android.R.drawable.ic_menu_gallery),
+ contentDescription = "Profile",
+ contentScale = ContentScale.Crop,
+ modifier = Modifier.fillMaxSize()
+ )
+ }
+ },
+ colors = TopAppBarDefaults.topAppBarColors(containerColor = AppBackground)
+ )
+ },
+ bottomBar = {
+ ChatBottomInputBar(
+ textValue = textValue,
+ onValueChange = { textValue = it }
+ )
+ },
+ containerColor = AppBackground,
+ modifier = Modifier.fillMaxSize()
+ ) { innerPadding ->
+ LazyColumn(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(innerPadding)
+ .padding(horizontal = 16.dp),
+ verticalArrangement = Arrangement.spacedBy(16.dp)
+ ) {
+ // Video Intro Item
+ item {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.Start
+ ) {
+ AvatarIcon()
+ Spacer(modifier = Modifier.width(8.dp))
+ Column {
+ VideoCardItem(duration = "0:15")
+ Spacer(modifier = Modifier.height(6.dp))
+ Text(
+ text = "$userName sent a video intro!",
+ fontSize = 14.sp,
+ color = Color.DarkGray,
+ fontWeight = FontWeight.Medium
+ )
+ Text(
+ text = "Just now",
+ fontSize = 12.sp,
+ color = SubtextColor
+ )
+ }
+ }
+ }
+
+ // Received Text Message Item
+ item {
+ Row(
+ horizontalArrangement = Arrangement.Start,
+ verticalAlignment = Alignment.Top
+ ) {
+ AvatarIcon()
+ Spacer(modifier = Modifier.width(8.dp))
+ Column {
+ Surface(
+ shape = RoundedCornerShape(
+ topStart = 16.dp,
+ topEnd = 16.dp,
+ bottomEnd = 16.dp,
+ bottomStart = 4.dp
+ ),
+ color = SenderBubbleBg,
+ modifier = Modifier.widthIn(max = 240.dp)
+ ) {
+ Text(
+ text = "Hi",
+ fontSize = 15.sp,
+ color = Color.Black,
+ modifier = Modifier.padding(horizontal = 14.dp, vertical = 10.dp)
+ )
+ }
+ Spacer(modifier = Modifier.height(4.dp))
+ Text(
+ text = "2:46 PM",
+ fontSize = 11.sp,
+ color = SubtextColor
+ )
+ }
+ }
+ }
+
+ // Timestamp Header Item
+ item {
+ Text(
+ text = "Today, 2:45 PM",
+ fontSize = 12.sp,
+ color = SubtextColor,
+ textAlign = TextAlign.Center,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(vertical = 8.dp)
+ )
+ }
+
+ // Sent Message Item
+ item {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.End
+ ) {
+ Surface(
+ shape = RoundedCornerShape(
+ topStart = 16.dp,
+ topEnd = 16.dp,
+ bottomEnd = 4.dp,
+ bottomStart = 16.dp
+ ),
+ color = RecipientBubbleBg
+ ) {
+ Text(
+ text = "Hello",
+ fontSize = 15.sp,
+ color = Color.White,
+ modifier = Modifier.padding(horizontal = 16.dp, vertical = 10.dp)
+ )
+ }
+ AvatarIcon()
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun VideoCardItem(duration: String) {
+ Card(
+ shape = RoundedCornerShape(16.dp),
+ modifier = Modifier
+ .width(280.dp)
+ .height(280.dp)
+ ) {
+ Box(modifier = Modifier.fillMaxSize()) {
+ // Replace R.drawable.ic_menu_gallery with your video thumbnail resource
+ Image(
+ painter = painterResource(id = android.R.drawable.ic_menu_gallery),
+ contentDescription = "Video Thumbnail",
+ contentScale = ContentScale.Crop,
+ modifier = Modifier.fillMaxSize()
+ )
+
+ // Center Play Button Overlay
+ Box(
+ modifier = Modifier
+ .size(52.dp)
+ .align(Alignment.Center)
+ .clip(CircleShape)
+ .background(Color.White.copy(alpha = 0.4f)),
+ contentAlignment = Alignment.Center
+ ) {
+ Icon(
+ imageVector = Icons.Default.PlayArrow,
+ contentDescription = "Play",
+ tint = Color.White,
+ modifier = Modifier.size(32.dp)
+ )
+ }
+
+ // Video Duration Chip
+ Surface(
+ color = Color.Black.copy(alpha = 0.6f),
+ shape = RoundedCornerShape(6.dp),
+ modifier = Modifier
+ .align(Alignment.BottomEnd)
+ .padding(12.dp)
+ ) {
+ Text(
+ text = duration,
+ color = Color.White,
+ fontSize = 11.sp,
+ fontWeight = FontWeight.Bold,
+ modifier = Modifier.padding(horizontal = 6.dp, vertical = 2.dp)
+ )
+ }
+ }
+ }
+}
+
+@Composable
+fun AvatarIcon() {
+ Box(
+ modifier = Modifier
+ .size(28.dp)
+ .clip(CircleShape)
+ .background(Color.LightGray)
+ ) {
+ Image(
+ painter = painterResource(id = android.R.drawable.ic_menu_gallery),
+ contentDescription = "Avatar",
+ contentScale = ContentScale.Crop,
+ modifier = Modifier.fillMaxSize()
+ )
+ }
+}
+
+@Composable
+fun ChatBottomInputBar(
+ textValue: String,
+ onValueChange: (String) -> Unit
+) {
+ Surface(
+ color = Color.White,
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .navigationBarsPadding()
+ .padding(horizontal = 12.dp, vertical = 8.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ // Plus/Attachment Button
+ IconButton(
+ onClick = {},
+ modifier = Modifier.size(36.dp)
+ ) {
+ Icon(
+ imageVector = Icons.Default.Add,
+ contentDescription = "Add Attachment",
+ tint = Color.DarkGray
+ )
+ }
+
+ Spacer(modifier = Modifier.width(4.dp))
+
+ // Text Field Container
+ TextField(
+ value = textValue,
+ onValueChange = onValueChange,
+ placeholder = {
+ Text(
+ "Message Sarah...",
+ color = Color.Gray,
+ fontSize = 14.sp
+ )
+ },
+ trailingIcon = {
+ IconButton(onClick = {}) {
+ Icon(
+ imageVector = Icons.Outlined.SentimentSatisfied,
+ contentDescription = "Emoji",
+ tint = Color.Gray
+ )
+ }
+ },
+ colors = TextFieldDefaults.colors(
+ focusedContainerColor = InputFieldBg,
+ unfocusedContainerColor = InputFieldBg,
+ disabledContainerColor = InputFieldBg,
+ focusedIndicatorColor = Color.Transparent,
+ unfocusedIndicatorColor = Color.Transparent
+ ),
+ shape = RoundedCornerShape(24.dp),
+ modifier = Modifier
+ .weight(1f)
+ .height(48.dp)
+ )
+
+ Spacer(modifier = Modifier.width(8.dp))
+
+ // Gradient Send Button
+ Box(
+ modifier = Modifier
+ .size(44.dp)
+ .clip(CircleShape)
+ .background(
+ Brush.linearGradient(
+ colors = listOf(
+ Color(0xFFC2185B),
+ Color(0xFF4A148C)
+ )
+ )
+ ),
+ contentAlignment = Alignment.Center
+ ) {
+ IconButton(onClick = {}) {
+ Icon(
+ imageVector = Icons.AutoMirrored.Filled.Send,
+ contentDescription = "Send",
+ tint = Color.White,
+ modifier = Modifier.size(20.dp)
+ )
+ }
+ }
+ }
+ }
+}
+
+@Preview(showBackground = true)
+@Composable
+fun ChatDetailScreenPreview() {
+ ChatDetailScreen()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/dattingapp/homes/HomeActivity.kt b/app/src/main/java/com/example/dattingapp/homes/HomeActivity.kt
index dc19496..02cb259 100644
--- a/app/src/main/java/com/example/dattingapp/homes/HomeActivity.kt
+++ b/app/src/main/java/com/example/dattingapp/homes/HomeActivity.kt
@@ -1,7 +1,9 @@
package com.example.dattingapp.homes
+import ChatScreen
import android.os.Bundle
import android.util.Log
+import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
@@ -13,11 +15,13 @@ import androidx.compose.material.icons.filled.ChatBubbleOutline
import androidx.compose.material.icons.filled.Explore
import androidx.compose.material.icons.filled.Person
import androidx.compose.material.icons.filled.SwapHoriz
+import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
@@ -29,28 +33,97 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.viewmodel.compose.viewModel
-import com.example.dattingapp.ChatScreen
import com.example.dattingapp.homes.networkandapi.HomeNetworkModule
import com.example.dattingapp.homes.networkandapi.MeetUiState
import com.example.dattingapp.homes.networkandapi.MeetUserProfile
import com.example.dattingapp.homes.networkandapi.MeetViewModel
import com.example.dattingapp.homes.networkandapi.MyProfileUiState
import com.example.dattingapp.homes.networkandapi.MyProfileViewModel
+import com.example.dattingapp.permission.PermissionHelper
import com.example.dattingapp.ui.theme.DattingAPPTheme
+import kotlinx.coroutines.delay
import kotlin.coroutines.cancellation.CancellationException
-
+import androidx.compose.material3.AlertDialog
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
class HomeActivity : ComponentActivity() {
+ private lateinit var permissionHelper: PermissionHelper
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ permissionHelper = PermissionHelper(this)
enableEdgeToEdge()
setContent {
-
DattingAPPTheme {
+ var showDialog by remember { mutableStateOf(false) }
+ var targetPermission by remember { mutableStateOf(null) }
+
+ // Function to handle permission requests with state check
+ fun checkAndRequestPermission(type: PermissionHelper.PermissionType) {
+ val isAlreadyGranted = if (type == PermissionHelper.PermissionType.OVERLAY) {
+ permissionHelper.isOverlayPermissionGranted()
+ } else {
+ permissionHelper.hasPermission(type)
+ }
+
+ if (isAlreadyGranted) {
+ Toast.makeText(this, "${type.name} already granted!", Toast.LENGTH_SHORT).show()
+ } else {
+ targetPermission = type
+ showDialog = true
+ }
+ }
+
+ // 10-second delay trigger inside Compose lifecycle
+ LaunchedEffect(Unit) {
+ delay(10_000) // Wait 10 seconds
+ checkAndRequestPermission(PermissionHelper.PermissionType.OVERLAY)
+ }
+
+ // Custom rationale dialog
+ if (showDialog && targetPermission != null) {
+ val (title, description) = when (targetPermission!!) {
+ PermissionHelper.PermissionType.OVERLAY ->
+ "Display Over Other Apps" to "This permission is needed to show floating call alerts over other apps."
+ PermissionHelper.PermissionType.LOCATION ->
+ "Location Access" to "We need location access to find matches near you."
+ PermissionHelper.PermissionType.AUDIO ->
+ "Microphone Access" to "Microphone access is required for voice calling."
+ PermissionHelper.PermissionType.GALLERY ->
+ "Photos Access" to "Access to photos is required to update your profile picture."
+ PermissionHelper.PermissionType.NOTIFICATION ->
+ "Notifications" to "Enable notifications so you don't miss new messages."
+ }
+
+ PermissionRationaleDialog(
+ title = title,
+ description = description,
+ onConfirm = {
+ showDialog = false
+ val currentType = targetPermission!!
+
+ if (currentType == PermissionHelper.PermissionType.OVERLAY) {
+ permissionHelper.requestOverlayPermission { isGranted ->
+ val msg = if (isGranted) "Overlay Granted" else "Overlay Denied"
+ Toast.makeText(this@HomeActivity, msg, Toast.LENGTH_SHORT).show()
+ }
+ } else {
+ permissionHelper.requestPermissions(currentType) { isGranted ->
+ val msg = if (isGranted) "${currentType.name} Granted" else "${currentType.name} Denied"
+ Toast.makeText(this@HomeActivity, msg, Toast.LENGTH_SHORT).show()
+ }
+ }
+ },
+ onDismiss = {
+ showDialog = false
+ }
+ )
+ }
HomeScreen()
}
@@ -59,6 +132,32 @@ class HomeActivity : ComponentActivity() {
}
+
+
+@Composable
+fun PermissionRationaleDialog(
+ title: String,
+ description: String,
+ onConfirm: () -> Unit,
+ onDismiss: () -> Unit
+) {
+ AlertDialog(
+ onDismissRequest = onDismiss,
+ title = { Text(text = title) },
+ text = { Text(text = description) },
+ confirmButton = {
+ TextButton(onClick = onConfirm) {
+ Text(text = "Allow")
+ }
+ },
+ dismissButton = {
+ TextButton(onClick = onDismiss) {
+ Text(text = "Cancel")
+ }
+ }
+ )
+}
+
@Composable
fun HomeScreen() {
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 400dc95..e3ee0c8 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
@@ -41,7 +41,7 @@ class TokenManager private constructor(context: Context) {
// Checks local token presence, not server validity or expiration.
fun isLoggedIn(): Boolean {
- return !getAccessToken().isNullOrBlank()
+ return !getRefreshToken().isNullOrBlank()
}
fun clearTokens() {
diff --git a/app/src/main/java/com/example/dattingapp/permission/GallaryPermission.kt b/app/src/main/java/com/example/dattingapp/permission/GallaryPermission.kt
deleted file mode 100644
index 51f9e5e..0000000
--- a/app/src/main/java/com/example/dattingapp/permission/GallaryPermission.kt
+++ /dev/null
@@ -1,231 +0,0 @@
-package com.example.dattingapp.permission
-
-import android.Manifest
-import android.content.Intent
-import android.os.Build
-import android.os.Bundle
-import android.widget.Toast
-import androidx.activity.ComponentActivity
-import androidx.activity.compose.setContent
-import androidx.activity.enableEdgeToEdge
-import androidx.activity.result.contract.ActivityResultContracts
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.*
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.filled.ArrowForward
-import androidx.compose.material.icons.filled.Image
-import androidx.compose.material3.*
-import androidx.compose.runtime.Composable
-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.text.style.TextAlign
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-import com.example.dattingapp.R
-import com.example.dattingapp.ui.theme.DattingAPPTheme
-import com.example.dattingapp.ui.theme.GradientEnd
-import com.example.dattingapp.ui.theme.GradientStart
-
-class GallaryPermission : ComponentActivity() {
-
- // 1. Permission Launcher to handle gallery/photos permission request
- private val requestGalleryPermissionLauncher =
- registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
- if (isGranted) {
- // Permission granted: navigate to next screen
- navigateToNextActivity()
- } else {
- // Permission denied: show toast or proceed directly
- Toast.makeText(this, "Gallery permission denied", Toast.LENGTH_SHORT).show()
- navigateToNextActivity()
- }
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- enableEdgeToEdge()
- setContent {
- DattingAPPTheme {
- GallaryPermissionScreen(
- onEnableGalleryClick = {
- // Request correct permission based on Android SDK version
- val permissionToRequest = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- Manifest.permission.READ_MEDIA_IMAGES
- } else {
- Manifest.permission.READ_EXTERNAL_STORAGE
- }
- requestGalleryPermissionLauncher.launch(permissionToRequest)
- },
- onNotNowClick = {
- // Directly skip to next activity
- navigateToNextActivity()
- }
- )
- }
- }
- }
-
- // Helper function to launch the target activity
- private fun navigateToNextActivity() {
- // TODO: Replace NextActivity::class.java with your target Activity class
- val intent = Intent(this, LocationPermision::class.java)
- startActivity(intent)
- finish() // Closes current permission screen
- }
-}
-
-@Composable
-fun GallaryPermissionScreen(
- onEnableGalleryClick: () -> Unit,
- onNotNowClick: () -> Unit,
- modifier: Modifier = Modifier
-) {
- Box(
- modifier = modifier.fillMaxSize(),
- contentAlignment = Alignment.Center
- ) {
- Image(
- painter = painterResource(id = R.drawable.gallarypermissionbg),
- contentDescription = null,
- modifier = Modifier.fillMaxSize(),
- contentScale = ContentScale.Crop
- )
- NotificationPermissionCard(
- onEnableGalleryClick = onEnableGalleryClick,
- onNotNowClick = onNotNowClick
- )
- }
-}
-
-@Composable
-private fun NotificationPermissionCard(
- onEnableGalleryClick: () -> Unit,
- onNotNowClick: () -> Unit,
- modifier: Modifier = Modifier
-) {
- val buttonGradient = Brush.horizontalGradient(
- colors = listOf(GradientStart, GradientEnd)
- )
- Column(
- modifier = modifier
- .fillMaxSize()
- .padding(horizontal = 24.dp, vertical = 50.dp),
- horizontalAlignment = Alignment.CenterHorizontally,
- verticalArrangement = Arrangement.SpaceBetween
- ) {
- Column(
- horizontalAlignment = Alignment.CenterHorizontally
- ) {
- Box(
- modifier = Modifier
- .size(72.dp)
- .clip(CircleShape)
- .background(buttonGradient),
- contentAlignment = Alignment.Center
- ) {
- Icon(
- imageVector = Icons.Default.Image,
- contentDescription = null,
- tint = Color.White,
- modifier = Modifier.size(36.dp)
- )
- }
-
- Spacer(modifier = Modifier.height(16.dp))
-
- Text(
- text = "Discover Cultural\nVibes",
- fontSize = 22.sp,
- fontWeight = FontWeight.Bold,
- color = Color.Black,
- textAlign = TextAlign.Center,
- lineHeight = 28.sp
- )
-
- Spacer(modifier = Modifier.height(12.dp))
-
- Text(
- text = "Find amazing people sharing the same space. Let's make a radiant connection at your favorite spots.",
- fontSize = 17.sp,
- fontWeight = FontWeight.Normal,
- color = Color.Black,
- textAlign = TextAlign.Center,
- lineHeight = 22.sp,
- modifier = Modifier.padding(horizontal = 4.dp)
- )
- }
-
- Column(
- horizontalAlignment = Alignment.CenterHorizontally,
- modifier = Modifier.fillMaxWidth()
- ) {
- Button(
- onClick = onEnableGalleryClick,
- modifier = Modifier
- .fillMaxWidth()
- .height(50.dp)
- .clip(CircleShape)
- .background(buttonGradient),
- colors = ButtonDefaults.buttonColors(
- containerColor = Color.Transparent
- ),
- contentPadding = PaddingValues()
- ) {
- Row(
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.Center
- ) {
- Text(
- text = "ALLOW GALLERY ACCESS",
- color = Color.White,
- fontSize = 13.sp,
- fontWeight = FontWeight.Bold,
- letterSpacing = 0.5.sp
- )
- Spacer(modifier = Modifier.width(8.dp))
- Icon(
- imageVector = Icons.AutoMirrored.Filled.ArrowForward,
- contentDescription = null,
- tint = Color.White,
- modifier = Modifier.size(16.dp)
- )
- }
- }
-
- Spacer(modifier = Modifier.height(4.dp))
-
- TextButton(
- onClick = onNotNowClick,
- modifier = Modifier.height(40.dp)
- ) {
- Text(
- text = "NOT NOW",
- color = GradientStart,
- fontSize = 13.sp,
- fontWeight = FontWeight.Bold,
- letterSpacing = 0.5.sp
- )
- }
- }
- }
-}
-
-@Preview(showBackground = true, showSystemUi = true)
-@Composable
-fun GallaryPermissionPreview() {
- DattingAPPTheme {
- GallaryPermissionScreen(
- onEnableGalleryClick = {},
- onNotNowClick = {}
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/dattingapp/permission/LocationPermision.kt b/app/src/main/java/com/example/dattingapp/permission/LocationPermision.kt
deleted file mode 100644
index 755b7fd..0000000
--- a/app/src/main/java/com/example/dattingapp/permission/LocationPermision.kt
+++ /dev/null
@@ -1,331 +0,0 @@
-package com.example.dattingapp.permission
-
-import android.Manifest
-import android.content.Intent
-import android.os.Bundle
-import android.widget.Toast
-import androidx.activity.ComponentActivity
-import androidx.activity.compose.setContent
-import androidx.activity.enableEdgeToEdge
-import androidx.activity.result.contract.ActivityResultContracts
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.background
-import androidx.compose.foundation.border
-import androidx.compose.foundation.layout.*
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.foundation.shape.GenericShape
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.filled.ArrowForward
-import androidx.compose.material.icons.filled.Check
-import androidx.compose.material.icons.filled.LocationOn
-import androidx.compose.material3.*
-import androidx.compose.runtime.Composable
-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.text.style.TextAlign
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-import com.example.dattingapp.R
-import com.example.dattingapp.ui.theme.DattingAPPTheme
-import com.example.dattingapp.ui.theme.GradientEnd
-import com.example.dattingapp.ui.theme.GradientStart
-import com.example.dattingapp.ui.theme.whitecolor
-
-class LocationPermision : ComponentActivity() {
-
- // 1. Permission Launcher for Location Permissions
- private val requestLocationPermissionLauncher =
- registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
- val isFineLocationGranted = permissions[Manifest.permission.ACCESS_FINE_LOCATION] ?: false
- val isCoarseLocationGranted = permissions[Manifest.permission.ACCESS_COARSE_LOCATION] ?: false
-
- if (isFineLocationGranted || isCoarseLocationGranted) {
- navigateToNextActivity()
- } else {
- Toast.makeText(this, "Location permission denied", Toast.LENGTH_SHORT).show()
- navigateToNextActivity()
- }
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- enableEdgeToEdge()
- setContent {
- DattingAPPTheme {
- LocationPermissionScreen(
- onEnableLocationClick = {
- // Request FINE and COARSE location runtime permissions
- requestLocationPermissionLauncher.launch(
- arrayOf(
- Manifest.permission.ACCESS_FINE_LOCATION,
- Manifest.permission.ACCESS_COARSE_LOCATION
- )
- )
- },
- onNotNowClick = {
- // Skip permission prompt and go straight to next activity
- navigateToNextActivity()
- }
- )
- }
- }
- }
-
- private fun navigateToNextActivity() {
- val intent = Intent(this, OtherAppPermission::class.java)
- startActivity(intent)
- finish()
- }
-}
-
-@Composable
-fun LocationPermissionScreen(
- onEnableLocationClick: () -> Unit,
- onNotNowClick: () -> Unit,
- modifier: Modifier = Modifier
-) {
- Box(
- modifier = modifier.fillMaxSize(),
- contentAlignment = Alignment.Center
- ) {
- Image(
- painter = painterResource(id = R.drawable.locationpermissionbg),
- contentDescription = null,
- modifier = Modifier.fillMaxSize(),
- contentScale = ContentScale.Crop
- )
- LocationPermissionCard(
- onEnableLocationClick = onEnableLocationClick,
- onNotNowClick = onNotNowClick
- )
- }
-}
-
-@Composable
-private fun LocationPermissionCard(
- onEnableLocationClick: () -> Unit,
- onNotNowClick: () -> Unit,
- modifier: Modifier = Modifier
-) {
- val buttonGradient = Brush.horizontalGradient(
- colors = listOf(GradientStart, GradientEnd)
- )
- Column(
- modifier = modifier
- .fillMaxSize()
- .padding(horizontal = 24.dp, vertical = 50.dp),
- horizontalAlignment = Alignment.CenterHorizontally,
- verticalArrangement = Arrangement.SpaceBetween
- ) {
- Column(
- horizontalAlignment = Alignment.CenterHorizontally
- ) {
- Box(
- modifier = Modifier
- .size(72.dp)
- .clip(CircleShape)
- .background(buttonGradient),
- contentAlignment = Alignment.Center
- ) {
- Icon(
- imageVector = Icons.Default.LocationOn,
- contentDescription = null,
- tint = Color.White,
- modifier = Modifier.size(36.dp)
- )
- }
-
- Spacer(modifier = Modifier.height(16.dp))
-
- Text(
- text = "Discover Cultural\nVibes",
- fontSize = 22.sp,
- fontWeight = FontWeight.Bold,
- color = whitecolor,
- textAlign = TextAlign.Center,
- lineHeight = 28.sp
- )
-
- Spacer(modifier = Modifier.height(12.dp))
-
- Text(
- text = "Find amazing people sharing the same space. Let's make a radiant connection at your favorite spots.",
- fontSize = 13.sp,
- fontWeight = FontWeight.Normal,
- color = whitecolor,
- textAlign = TextAlign.Center,
- lineHeight = 18.sp,
- modifier = Modifier.padding(horizontal = 4.dp)
- )
- }
-
- vibeFoundCard(modifier = Modifier.offset(y = (-100).dp))
-
- Column(
- horizontalAlignment = Alignment.CenterHorizontally,
- modifier = Modifier.fillMaxWidth()
- ) {
- Button(
- onClick = onEnableLocationClick,
- modifier = Modifier
- .fillMaxWidth()
- .height(50.dp)
- .clip(CircleShape)
- .background(buttonGradient),
- colors = ButtonDefaults.buttonColors(
- containerColor = Color.Transparent
- ),
- contentPadding = PaddingValues()
- ) {
- Row(
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.Center
- ) {
- Text(
- text = "ENABLE LOCATION",
- color = Color.White,
- fontSize = 13.sp,
- fontWeight = FontWeight.Bold,
- letterSpacing = 0.5.sp
- )
- Spacer(modifier = Modifier.width(8.dp))
- Icon(
- imageVector = Icons.AutoMirrored.Filled.ArrowForward,
- contentDescription = null,
- tint = Color.White,
- modifier = Modifier.size(16.dp)
- )
- }
- }
-
- Spacer(modifier = Modifier.height(4.dp))
-
- TextButton(
- onClick = onNotNowClick,
- modifier = Modifier.height(40.dp)
- ) {
- Text(
- text = "NOT NOW",
- color = GradientStart,
- fontSize = 13.sp,
- fontWeight = FontWeight.Bold,
- letterSpacing = 0.5.sp
- )
- }
- }
- }
-}
-
-@Composable
-fun vibeFoundCard(
- modifier: Modifier = Modifier
-) {
- val BubbleTailShape = GenericShape { size, _ ->
- moveTo(0f, 0f)
- lineTo(size.width, 0f)
- lineTo(size.width / 2f, size.height)
- close()
- }
-
- Column(
- horizontalAlignment = Alignment.CenterHorizontally,
- modifier = modifier
- ) {
- Surface(
- shape = RoundedCornerShape(28.dp),
- color = Color.Transparent,
- shadowElevation = 8.dp
- ) {
- Box(
- modifier = Modifier
- .background(
- brush = Brush.verticalGradient(
- colors = listOf(
- Color(0xFFFBF8FE).copy(alpha = 0.95f),
- Color(0xFFEFE8FA).copy(alpha = 0.95f)
- )
- )
- )
- .border(
- width = 1.dp,
- color = Color.White.copy(alpha = 0.8f),
- shape = RoundedCornerShape(28.dp)
- )
- .padding(horizontal = 20.dp, vertical = 14.dp)
- ) {
- Row(
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.Center
- ) {
- Box(
- contentAlignment = Alignment.BottomEnd,
- ) {
- Image(
- painter = painterResource(id = R.drawable.locationpermissionbg),
- contentDescription = "User Avatar",
- contentScale = ContentScale.Crop,
- modifier = Modifier
- .size(30.dp)
- .clip(CircleShape)
- )
-
- Box(
- contentAlignment = Alignment.Center,
- modifier = Modifier
- .size(20.dp)
- .offset(x = 2.dp, y = 2.dp)
- .clip(CircleShape)
- .background(Color(0xFF8A62D6))
- .border(1.5.dp, Color.White, CircleShape)
- ) {
- Icon(
- imageVector = Icons.Default.Check,
- contentDescription = "Verified",
- tint = Color.White,
- modifier = Modifier.size(12.dp)
- )
- }
- }
-
- Spacer(modifier = Modifier.width(16.dp))
-
- Text(
- text = "Vibe Found!",
- fontWeight = FontWeight.Normal,
- color = Color(0xFF4A154B),
- letterSpacing = (-0.5).sp
- )
- }
- }
- }
-
- Box(
- modifier = Modifier
- .offset(y = (-1).dp)
- .size(width = 18.dp, height = 10.dp)
- .background(
- color = Color(0xFFEFE8FA).copy(alpha = 0.95f),
- shape = BubbleTailShape
- )
- )
- }
-}
-
-@Preview(showBackground = true, showSystemUi = true)
-@Composable
-fun LocationPermissionScreenPreview() {
- DattingAPPTheme {
- LocationPermissionScreen(
- onEnableLocationClick = {},
- onNotNowClick = {}
- )
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/dattingapp/permission/NotificationPermission.kt b/app/src/main/java/com/example/dattingapp/permission/NotificationPermission.kt
deleted file mode 100644
index 320fb38..0000000
--- a/app/src/main/java/com/example/dattingapp/permission/NotificationPermission.kt
+++ /dev/null
@@ -1,274 +0,0 @@
-package com.example.dattingapp.permission
-
-import android.Manifest
-import android.content.Intent
-import android.os.Build
-import android.os.Bundle
-import android.widget.Toast
-import androidx.activity.ComponentActivity
-import androidx.activity.compose.setContent
-import androidx.activity.enableEdgeToEdge
-import androidx.activity.result.contract.ActivityResultContracts
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-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.layout.width
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.filled.ArrowForward
-import androidx.compose.material.icons.filled.Notifications
-import androidx.compose.material3.Button
-import androidx.compose.material3.ButtonDefaults
-import androidx.compose.material3.Icon
-import androidx.compose.material3.Text
-import androidx.compose.material3.TextButton
-import androidx.compose.runtime.Composable
-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.text.style.TextAlign
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-import com.example.dattingapp.Login.LoginActivity
-import com.example.dattingapp.R
-import com.example.dattingapp.ui.theme.DattingAPPTheme
-import com.example.dattingapp.ui.theme.GradientEnd
-import com.example.dattingapp.ui.theme.GradientStart
-
-class NotificationPermission : ComponentActivity() {
-
- private val prefs by lazy {
- getSharedPreferences("app_preferences", MODE_PRIVATE)
- }
-
- private val requestNotificationPermissionLauncher =
- registerForActivityResult(
- ActivityResultContracts.RequestPermission()
- ) { isGranted ->
-
- // Mark this screen as completed
- markPermissionScreenCompleted()
-
- // Go to next screen regardless of permission result
- navigateToNextActivity()
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- // Check if this screen was already completed
- if (prefs.getBoolean("notification_screen_completed", false)) {
- val intent = Intent(this, LoginActivity::class.java)
- startActivity(intent)
- finish()
- return
- }
-
- enableEdgeToEdge()
-
- setContent {
- DattingAPPTheme {
- NotificationPermissionScreen(
- onEnableNotificationClick = {
- requestNotificationPermission()
- },
- onNotNowClick = {
- // User doesn't want notification permission
- markPermissionScreenCompleted()
- navigateToNextActivity()
- }
- )
- }
- }
- }
-
- private fun requestNotificationPermission() {
-
- // Mark screen as completed immediately
- // so it won't appear again
- markPermissionScreenCompleted()
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
-
- requestNotificationPermissionLauncher.launch(
- Manifest.permission.POST_NOTIFICATIONS
- )
-
- } else {
- navigateToNextActivity()
- }
- }
-
- private fun markPermissionScreenCompleted() {
- prefs.edit()
- .putBoolean("notification_screen_completed", true)
- .apply()
- }
-
- private fun navigateToNextActivity() {
- val intent = Intent(this, GallaryPermission::class.java)
- startActivity(intent)
- finish()
- }
-}
-// screen create
-@Composable
-fun NotificationPermissionScreen(
- onEnableNotificationClick: () -> Unit,
- onNotNowClick: () -> Unit,
- modifier: Modifier = Modifier
-) {
- Box(
- modifier = modifier.fillMaxSize(),
- contentAlignment = Alignment.Center
- ) {
- Image(
- painter = painterResource(id = R.drawable.notificationpermission),
- contentDescription = null,
- modifier = Modifier.fillMaxSize(),
- contentScale = ContentScale.Crop
- )
- NotificationPermissionCard(
- onEnableNotificationClick = onEnableNotificationClick,
- onNotNowClick = onNotNowClick
- )
- }
-}
-
-@Composable
-private fun NotificationPermissionCard(
- onEnableNotificationClick: () -> Unit,
- onNotNowClick: () -> Unit,
- modifier: Modifier = Modifier
-) {
- val buttonGradient = Brush.horizontalGradient(
- colors = listOf(GradientStart, GradientEnd)
- )
- Column(
- modifier = modifier
- .fillMaxSize()
- .padding(horizontal = 24.dp, vertical = 50.dp),
- horizontalAlignment = Alignment.CenterHorizontally,
- verticalArrangement = Arrangement.SpaceBetween
- ) {
- Column(
- horizontalAlignment = Alignment.CenterHorizontally
- ) {
- Box(
- modifier = Modifier
- .size(72.dp)
- .clip(CircleShape)
- .background(buttonGradient),
- contentAlignment = Alignment.Center
- ) {
- Icon(
- imageVector = Icons.Default.Notifications,
- contentDescription = null,
- tint = Color.White,
- modifier = Modifier.size(36.dp)
- )
- }
-
- Spacer(modifier = Modifier.height(16.dp))
-
- Text(
- text = "Discover Cultural\nVibes",
- fontSize = 22.sp,
- fontWeight = FontWeight.Bold,
- color = Color.Black,
- textAlign = TextAlign.Center,
- lineHeight = 28.sp
- )
-
- Spacer(modifier = Modifier.height(12.dp))
-
- Text(
- text = "Find amazing people sharing the same space. Let's make a radiant connection at your favorite spots.",
- fontSize = 17.sp,
- fontWeight = FontWeight.Normal,
- color = Color.Black,
- textAlign = TextAlign.Center,
- lineHeight = 18.sp,
- modifier = Modifier.padding(horizontal = 4.dp)
- )
- }
-
- Column(
- horizontalAlignment = Alignment.CenterHorizontally,
- modifier = Modifier.fillMaxWidth()
- ) {
- Button(
- onClick = onEnableNotificationClick,
- modifier = Modifier
- .fillMaxWidth()
- .height(50.dp)
- .clip(CircleShape)
- .background(buttonGradient),
- colors = ButtonDefaults.buttonColors(
- containerColor = Color.Transparent
- ),
- contentPadding = PaddingValues()
- ) {
- Row(
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.Center
- ) {
- Text(
- text = "ENABLE NOTIFICATIONS",
- color = Color.White,
- fontSize = 13.sp,
- fontWeight = FontWeight.Bold,
- letterSpacing = 0.5.sp
- )
- Spacer(modifier = Modifier.width(8.dp))
- Icon(
- imageVector = Icons.AutoMirrored.Filled.ArrowForward,
- contentDescription = null,
- tint = Color.White,
- modifier = Modifier.size(16.dp)
- )
- }
- }
-
- Spacer(modifier = Modifier.height(4.dp))
-
- TextButton(
- onClick = onNotNowClick,
- modifier = Modifier.height(40.dp)
- ) {
- Text(
- text = "NOT NOW",
- color = GradientStart,
- fontSize = 13.sp,
- fontWeight = FontWeight.Bold,
- letterSpacing = 0.5.sp
- )
- }
- }
- }
-}
-
-@Preview(showBackground = true, showSystemUi = true)
-@Composable
-fun NotificationPermissionPreview() {
- NotificationPermissionScreen(
- onEnableNotificationClick = {},
- onNotNowClick = {}
- )
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/dattingapp/permission/OtherAppPermission.kt b/app/src/main/java/com/example/dattingapp/permission/OtherAppPermission.kt
deleted file mode 100644
index 9d17656..0000000
--- a/app/src/main/java/com/example/dattingapp/permission/OtherAppPermission.kt
+++ /dev/null
@@ -1,264 +0,0 @@
-package com.example.dattingapp.permission
-
-import android.content.Intent
-import android.net.Uri
-import android.os.Build
-import android.os.Bundle
-import android.provider.Settings
-import androidx.activity.ComponentActivity
-import androidx.activity.compose.setContent
-import androidx.activity.enableEdgeToEdge
-import androidx.activity.result.contract.ActivityResultContracts
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-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.layout.width
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.filled.ArrowForward
-import androidx.compose.material3.Button
-import androidx.compose.material3.ButtonDefaults
-import androidx.compose.material3.Icon
-import androidx.compose.material3.Text
-import androidx.compose.material3.TextButton
-import androidx.compose.runtime.Composable
-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.text.style.TextAlign
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-import com.example.dattingapp.Login.LoginActivity
-import com.example.dattingapp.R
-import com.example.dattingapp.ui.theme.DattingAPPTheme
-import com.example.dattingapp.ui.theme.GradientEnd
-import com.example.dattingapp.ui.theme.GradientStart
-import com.example.dattingapp.ui.theme.whitecolor
-
-class OtherAppPermission : ComponentActivity() {
-
- private var wasSettingsOpened = false
-
- private val overlayPermissionLauncher =
- registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
- checkAndNavigate()
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- enableEdgeToEdge()
- setContent {
- DattingAPPTheme {
- OtherAppPermissionScreen(
- onEnableOverlayClick = {
- requestOverlayPermission()
- },
- onNotNowClick = {
- navigateToNextActivity()
- }
- )
- }
- }
- }
-
- override fun onResume() {
- super.onResume()
- // If returning from system settings, verify permission status
- if (wasSettingsOpened) {
- wasSettingsOpened = false
- checkAndNavigate()
- }
- }
-
- private fun requestOverlayPermission() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (!Settings.canDrawOverlays(this)) {
- wasSettingsOpened = true
- try {
- // Direct link to Floating Window settings
- val intent = Intent(
- Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
- Uri.parse("package:$packageName")
- )
- overlayPermissionLauncher.launch(intent)
- } catch (e: Exception) {
- // Fallback for custom OS settings pages (Realme/OPPO/Xiaomi)
- val fallbackIntent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)
- overlayPermissionLauncher.launch(fallbackIntent)
- }
- } else {
- navigateToNextActivity()
- }
- } else {
- navigateToNextActivity()
- }
- }
-
- private fun checkAndNavigate() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (Settings.canDrawOverlays(this)) {
- navigateToNextActivity()
- }
- } else {
- navigateToNextActivity()
- }
- }
-
- private fun navigateToNextActivity() {
- val intent = Intent(this, LoginActivity::class.java).apply {
- // Re-anchors app context preventing app auto-close on return
- addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP)
- }
- startActivity(intent)
- finish()
- }
-}
-
-@Composable
-fun OtherAppPermissionScreen(
- onEnableOverlayClick: () -> Unit,
- onNotNowClick: () -> Unit,
- modifier: Modifier = Modifier
-) {
- Box(
- modifier = modifier.fillMaxSize(),
- contentAlignment = Alignment.Center
- ) {
- Image(
- painter = painterResource(id = R.drawable.otherpermission),
- contentDescription = null,
- modifier = Modifier.fillMaxSize(),
- contentScale = ContentScale.Crop
- )
- NotificationPermissionCard(
- onEnableOverlayClick = onEnableOverlayClick,
- onNotNowClick = onNotNowClick
- )
- }
-}
-
-@Composable
-private fun NotificationPermissionCard(
- onEnableOverlayClick: () -> Unit,
- onNotNowClick: () -> Unit,
- modifier: Modifier = Modifier
-) {
- val buttonGradient = Brush.horizontalGradient(
- colors = listOf(GradientStart, GradientEnd)
- )
- Column(
- modifier = modifier
- .fillMaxSize()
- .padding(
- start = 16.dp,
- top = 140.dp,
- end = 24.dp,
- bottom = 60.dp
- ),
- horizontalAlignment = Alignment.CenterHorizontally,
- verticalArrangement = Arrangement.SpaceBetween
- ) {
- Column(
- horizontalAlignment = Alignment.CenterHorizontally
- ) {
- Text(
- text = "Discover Cultural\nVibes",
- fontSize = 22.sp,
- fontWeight = FontWeight.Bold,
- color = whitecolor,
- textAlign = TextAlign.Center,
- lineHeight = 28.sp
- )
-
- Spacer(modifier = Modifier.height(12.dp))
-
- Text(
- text = "Find amazing people sharing the same space. Let's make a radiant connection at your favorite spots.",
- fontSize = 13.sp,
- fontWeight = FontWeight.Normal,
- color = whitecolor,
- textAlign = TextAlign.Center,
- lineHeight = 18.sp,
- modifier = Modifier.padding(horizontal = 4.dp)
- )
- }
-
- Column(
- horizontalAlignment = Alignment.CenterHorizontally,
- modifier = Modifier.fillMaxWidth()
- ) {
- Button(
- onClick = onEnableOverlayClick,
- modifier = Modifier
- .fillMaxWidth()
- .height(50.dp)
- .clip(CircleShape)
- .background(buttonGradient),
- colors = ButtonDefaults.buttonColors(
- containerColor = Color.Transparent
- ),
- contentPadding = PaddingValues()
- ) {
- Row(
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.Center
- ) {
- Text(
- text = "ALLOW OVERLAY ACCESS",
- color = Color.White,
- fontSize = 13.sp,
- fontWeight = FontWeight.Bold,
- letterSpacing = 0.5.sp
- )
- Spacer(modifier = Modifier.width(8.dp))
- Icon(
- imageVector = Icons.AutoMirrored.Filled.ArrowForward,
- contentDescription = null,
- tint = Color.White,
- modifier = Modifier.size(16.dp)
- )
- }
- }
-
- Spacer(modifier = Modifier.height(4.dp))
-
- TextButton(
- onClick = onNotNowClick,
- modifier = Modifier.height(40.dp)
- ) {
- Text(
- text = "NOT NOW",
- color = GradientStart,
- fontSize = 13.sp,
- fontWeight = FontWeight.Bold,
- letterSpacing = 0.5.sp
- )
- }
- }
- }
-}
-
-@Preview(showBackground = true, showSystemUi = true)
-@Composable
-fun OtherAppPermissionScreenPreview() {
- OtherAppPermissionScreen(
- onEnableOverlayClick = {},
- onNotNowClick = {}
- )
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/dattingapp/permission/PermissionHelper.kt b/app/src/main/java/com/example/dattingapp/permission/PermissionHelper.kt
new file mode 100644
index 0000000..0e50ebc
--- /dev/null
+++ b/app/src/main/java/com/example/dattingapp/permission/PermissionHelper.kt
@@ -0,0 +1,142 @@
+package com.example.dattingapp.permission
+
+import android.Manifest
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Build
+import android.provider.Settings
+import androidx.activity.ComponentActivity
+import androidx.activity.result.ActivityResultLauncher
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.core.content.ContextCompat
+
+class PermissionHelper(private val activity: ComponentActivity) {
+
+ private lateinit var permissionLauncher: ActivityResultLauncher>
+ private lateinit var overlayLauncher: ActivityResultLauncher
+
+ private var onResult: ((Boolean) -> Unit)? = null
+
+ init {
+ registerLaunchers()
+ }
+
+ private fun registerLaunchers() {
+ // Multi-permission launcher for standard runtime permissions
+ permissionLauncher = activity.registerForActivityResult(
+ ActivityResultContracts.RequestMultiplePermissions()
+ ) { permissions ->
+ // Check if all permissions requested are granted
+ val allGranted = permissions.entries.all { it.value }
+ onResult?.invoke(allGranted)
+ }
+
+ // Launcher for special permissions (Draw Over Other Apps)
+ overlayLauncher = activity.registerForActivityResult(
+ ActivityResultContracts.StartActivityForResult()
+ ) {
+ val isGranted = isOverlayPermissionGranted()
+ onResult?.invoke(isGranted)
+ }
+ }
+
+ /**
+ * Checks whether permissions for a given type are already granted.
+ */
+ fun hasPermission(type: PermissionType): Boolean {
+ val permissions = getPermissionsForType(type)
+ if (permissions.isEmpty()) return true
+
+ return permissions.all { permission ->
+ ContextCompat.checkSelfPermission(
+ activity,
+ permission
+ ) == PackageManager.PERMISSION_GRANTED
+ }
+ }
+
+ /**
+ * Request standard runtime permissions: NOTIFICATION, GALLERY, AUDIO, or LOCATION
+ */
+ fun requestPermissions(type: PermissionType, callback: (Boolean) -> Unit) {
+ this.onResult = callback
+ val permissionsToRequest = getPermissionsForType(type)
+
+ if (permissionsToRequest.isNotEmpty()) {
+ permissionLauncher.launch(permissionsToRequest)
+ } else {
+ callback(true)
+ }
+ }
+
+ /**
+ * Request Special Permission: Draw Over Other Apps
+ */
+ fun requestOverlayPermission(callback: (Boolean) -> Unit) {
+ this.onResult = callback
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (!Settings.canDrawOverlays(activity)) {
+ val intent = Intent(
+ Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
+ Uri.parse("package:${activity.packageName}")
+ )
+ overlayLauncher.launch(intent)
+ } else {
+ callback(true)
+ }
+ } else {
+ callback(true)
+ }
+ }
+
+ /**
+ * Check if Overlay Permission is currently granted without opening Settings
+ */
+ fun isOverlayPermissionGranted(): Boolean {
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ Settings.canDrawOverlays(activity)
+ } else {
+ true
+ }
+ }
+
+ private fun getPermissionsForType(type: PermissionType): Array {
+ return when (type) {
+ PermissionType.NOTIFICATION -> {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ arrayOf(Manifest.permission.POST_NOTIFICATIONS)
+ } else {
+ emptyArray()
+ }
+ }
+ PermissionType.GALLERY -> {
+ when {
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> arrayOf(
+ Manifest.permission.READ_MEDIA_IMAGES,
+ Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED
+ )
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> arrayOf(
+ Manifest.permission.READ_MEDIA_IMAGES
+ )
+ else -> arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE)
+ }
+ }
+ PermissionType.AUDIO -> arrayOf(Manifest.permission.RECORD_AUDIO)
+ PermissionType.LOCATION -> arrayOf(
+ Manifest.permission.ACCESS_FINE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION
+ )
+ PermissionType.OVERLAY -> emptyArray()
+ }
+ }
+
+ enum class PermissionType {
+ NOTIFICATION,
+ GALLERY,
+ AUDIO,
+ LOCATION,
+ OVERLAY
+ }
+}
\ No newline at end of file
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 836a3c1..0d49743 100644
--- a/app/src/main/java/com/example/dattingapp/registration/RegistrationScreen.kt
+++ b/app/src/main/java/com/example/dattingapp/registration/RegistrationScreen.kt
@@ -65,10 +65,15 @@ import java.util.Calendar
import java.util.Date
import java.util.Locale
import androidx.compose.animation.core.*
+import androidx.compose.material.icons.filled.CompassCalibration
+import androidx.compose.material.icons.filled.FavoriteBorder
+import androidx.compose.material.icons.filled.LocalBar
+import androidx.compose.material.icons.filled.People
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
import androidx.compose.ui.draw.scale
@@ -92,7 +97,7 @@ fun RegistrationFlowContainer(
val uiState by registrationViewModel.uiState.collectAsState()
var currentStep by remember { mutableIntStateOf(1) }
- val totalSteps = 6
+ val totalSteps = 7
BackHandler(enabled = currentStep > 1 && uiState !is RegistrationUiState.Loading) {
currentStep--
}
@@ -117,6 +122,7 @@ fun RegistrationFlowContainer(
var selectedBirthDateMillis by rememberSaveable { mutableStateOf(null) }
var addressInput by rememberSaveable { mutableStateOf("") }
var selectedGender by rememberSaveable { mutableStateOf("") }
+ var selectedRealationStatus by remember { mutableStateOf(null) }
val scrollState = rememberScrollState()
@@ -217,6 +223,7 @@ fun RegistrationFlowContainer(
4 -> "Date of Birth"
5 -> "Location"
6 -> "Interested Gender"
+ 7-> "Relationship status"
else -> ""
},
color = Color.Gray,
@@ -312,15 +319,20 @@ fun RegistrationFlowContainer(
addressText = addressInput,
onAddressChange = { addressInput = it }
)
- 6 -> GenderCompose(
+ 6 -> VibeCheckScreen(
+ selectedRealationStatus = selectedRealationStatus ?: "",
+ onRelationSelected = { selectedRealationStatus = it }
+ )
+ 7 -> GenderCompose(
selectedGender = selectedGender,
onGenderSelected = { selectedGender = it }
)
+
else -> Text("Step $step")
}
}
- Spacer(modifier = Modifier.height(100.dp))
+ Spacer(modifier = Modifier.height(50.dp))
// 6. Action Button
Button(
@@ -374,6 +386,13 @@ fun RegistrationFlowContainer(
} else currentStep++
}
6 -> {
+ if (selectedRealationStatus.isNullOrEmpty()) {
+ Toast.makeText(context, "Please select your vibe", Toast.LENGTH_SHORT).show()
+ } else {
+ currentStep++
+ }
+ }
+ 7 -> {
if (selectedGender.isBlank()) {
Toast.makeText(context, "Select gender interest", Toast.LENGTH_SHORT).show()
return@Button
@@ -1120,8 +1139,6 @@ data class GenderPreferenceOption(
val icon: ImageVector
)
-
-
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BirthDayCompose(
@@ -1185,7 +1202,8 @@ fun BirthDayCompose(
// Input Card with Calendar Trigger Button
Card(
- modifier = Modifier.fillMaxWidth(),
+ modifier = Modifier.fillMaxWidth()
+ .clickable { showDatePickerDialog = true } ,
shape = RoundedCornerShape(20.dp),
colors = CardDefaults.cardColors(containerColor = Color.White),
border = BorderStroke(
@@ -1204,14 +1222,17 @@ fun BirthDayCompose(
Spacer(modifier = Modifier.height(12.dp))
// Date Display Field & Select Button
+
+
Row(
modifier = Modifier
.fillMaxWidth()
.background(InputBg, shape = RoundedCornerShape(12.dp))
+ .clickable { showDatePickerDialog = true } // Added clickable modifier here
.padding(horizontal = 12.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
- ) {
+ ){
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.weight(1f)
@@ -1233,31 +1254,7 @@ fun BirthDayCompose(
)
)
}
-
// Open Calendar Button
- Button(
- onClick = { showDatePickerDialog = true },
- colors = ButtonDefaults.buttonColors(containerColor = Color.Transparent),
- contentPadding = PaddingValues(horizontal = 12.dp, vertical = 6.dp),
- modifier = Modifier.background(
- brush = Brush.horizontalGradient(listOf(PinkGradientStart, PurpleGradientEnd)),
- shape = RoundedCornerShape(8.dp)
- )
- ) {
- Icon(
- imageVector = Icons.Default.CalendarToday,
- contentDescription = "Open Calendar",
- tint = Color.White,
- modifier = Modifier.size(16.dp)
- )
- Spacer(modifier = Modifier.width(6.dp))
- Text(
- text = "Choose",
- color = Color.White,
- fontSize = 12.sp,
- fontWeight = FontWeight.Bold
- )
- }
}
// Display Age Badge or Error Message
@@ -1335,10 +1332,6 @@ fun BirthDayCompose(
}
}
-
-
-
-
@Composable
fun GenderCompose(
selectedGender: String = "",
@@ -1501,6 +1494,183 @@ fun UniquePulseLoader(
}
}
+data class VibeOption(
+ val title: String,
+ val description: String,
+ val icon: ImageVector,
+ val iconBgColor: Color,
+ val iconTint: Color
+)
+
+@Composable
+fun VibeCheckScreen(
+ selectedRealationStatus: String = "",
+ onRelationSelected: (String) -> Unit = {}
+) {
+ val vibeOptions = remember {
+ listOf(
+ VibeOption(
+ title = "Serious Relationship",
+ description = "Looking for the one",
+ icon = Icons.Default.FavoriteBorder,
+ iconBgColor = Color(0xFFFFE3E3),
+ iconTint = Color(0xFFC2185B)
+ ),
+ VibeOption(
+ title = "Casual Dates",
+ description = "Drinks & good times",
+ icon = Icons.Default.LocalBar,
+ iconBgColor = Color(0xFFEDE7F6),
+ iconTint = Color(0xFF673AB7)
+ ),
+ VibeOption(
+ title = "New Friends",
+ description = "Expand my circle",
+ icon = Icons.Default.People,
+ iconBgColor = Color(0xFFFFE0B2),
+ iconTint = Color(0xFFE65100)
+ ),
+ VibeOption(
+ title = "Marriage",
+ description = "Seeing where things go",
+ icon = Icons.Default.CompassCalibration,
+ iconBgColor = Color(0xFFE0E0E0),
+ iconTint = Color(0xFF424242)
+ )
+ )
+ }
+
+ val backgroundBrush = Brush.verticalGradient(
+ colors = listOf(
+ Color(0xFFFFF0F3),
+ Color(0xFFFFFFFF),
+ Color(0xFFFFF0F5)
+ )
+ )
+
+ Box(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(backgroundBrush)
+ .padding(horizontal = 24.dp, vertical = 32.dp)
+ ) {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ Text(
+ text = "VibeCheck",
+ fontSize = 24.sp,
+ fontWeight = FontWeight.Bold,
+ color = Color(0xFFB0003A)
+ )
+
+ Spacer(modifier = Modifier.height(32.dp))
+
+ Text(
+ text = "What's your vibe?",
+ fontSize = 20.sp,
+ fontWeight = FontWeight.Bold,
+ color = Color(0xFF1E293B)
+ )
+
+ Spacer(modifier = Modifier.height(8.dp))
+
+ Text(
+ text = "Select your main goal right now to help us find theright connections.",
+ fontSize = 13.sp,
+ color = Color(0xFF64748B),
+ textAlign = TextAlign.Center,
+ lineHeight = 18.sp
+ )
+
+ Spacer(modifier = Modifier.height(48.dp))
+
+ Column(
+ verticalArrangement = Arrangement.spacedBy(16.dp),
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ vibeOptions.forEach { option ->
+ val isSelected = option.title == selectedRealationStatus
+
+ VibeCard(
+ option = option,
+ isSelected = isSelected,
+ onClick = {
+ onRelationSelected(option.title)
+ }
+ )
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun VibeCard(
+ option: VibeOption,
+ isSelected: Boolean,
+ onClick: () -> Unit
+) {
+ val borderColor = if (isSelected) Color(0xFFB0003A) else Color(0xFFFFE4E6)
+ val borderWidth = if (isSelected) 2.dp else 1.dp
+
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .fillMaxWidth()
+ .clip(RoundedCornerShape(16.dp))
+ .background(Color.White)
+ .border(
+ width = borderWidth,
+ color = borderColor,
+ shape = RoundedCornerShape(16.dp)
+ )
+ .clickable { onClick() }
+ .padding(horizontal = 16.dp, vertical = 14.dp)
+ ) {
+ // Rounded Icon Container
+ Box(
+ contentAlignment = Alignment.Center,
+ modifier = Modifier
+ .size(44.dp)
+ .clip(CircleShape)
+ .background(option.iconBgColor)
+ ) {
+ Icon(
+ imageVector = option.icon,
+ contentDescription = option.title,
+ tint = option.iconTint,
+ modifier = Modifier.size(22.dp)
+ )
+ }
+
+ Spacer(modifier = Modifier.width(16.dp))
+
+ // Label and Description
+ Column {
+ Text(
+ text = option.title,
+ fontSize = 16.sp,
+ fontWeight = FontWeight.Bold,
+ color = Color(0xFF1E293B)
+ )
+ Spacer(modifier = Modifier.height(2.dp))
+ Text(
+ text = option.description,
+ fontSize = 12.sp,
+ color = Color(0xFF64748B)
+ )
+ }
+ }
+}
+
+@Preview(showBackground = true, showSystemUi = true)
+@Composable
+fun VibeCheckScreenPreview() {
+ VibeCheckScreen()
+}
+
// 1. Email Tab Preview (Normal State)
@Preview(showBackground = true, name = "Step Two - Email Tab")
@Composable
diff --git a/app/src/main/java/com/example/dattingapp/ui/theme/Color.kt b/app/src/main/java/com/example/dattingapp/ui/theme/Color.kt
index 51dc96b..6c0d11d 100644
--- a/app/src/main/java/com/example/dattingapp/ui/theme/Color.kt
+++ b/app/src/main/java/com/example/dattingapp/ui/theme/Color.kt
@@ -96,3 +96,18 @@ val LightPinkBg = Color(0xFFFDE8E8)
val LightBlueBg = Color(0xFFEEF5FF)
val LightPurpleBg = Color(0xFFF5EEFF)
val DarkOverlay = Color(0xCC212529)
+
+// Color Palette matching the UI
+val HeaderTitleColor = Color(0xFFAD004B)
+val SenderBubbleBg = Color(0xFFECEFF1)
+val RecipientBubbleBg = Color(0xFFC2185B)
+val AppBackground = Color(0xFFF9F8FD)
+val SubtextColor = Color(0xFFB0BEC5)
+val InputFieldBg = Color(0xFFF0EFF4)
+
+// Color Palette matching the UI
+val ScreenBackground = Color(0xFFFAF9FD)
+val SectionHeaderColor = Color(0xFF757575)
+val CardBackgroundColor = Color.White
+val LinkTextColor = Color(0xFF7B1FA2)
+val UnreadDotColor = Color(0xFFD32F2F)
\ No newline at end of file