Browse Source

refoctor the code

master
osman160128 4 weeks ago
parent
commit
4140b989c8
  1. 28
      app/src/main/AndroidManifest.xml
  2. 623
      app/src/main/java/com/example/dattingapp/ChatScreen.kt
  3. 252
      app/src/main/java/com/example/dattingapp/LikeAndMatchScreen.kt
  4. 10
      app/src/main/java/com/example/dattingapp/Login/LoginActivity.kt
  5. 34
      app/src/main/java/com/example/dattingapp/MainActivity.kt
  6. 385
      app/src/main/java/com/example/dattingapp/chat/PersonChatScreen.kt
  7. 105
      app/src/main/java/com/example/dattingapp/homes/HomeActivity.kt
  8. 2
      app/src/main/java/com/example/dattingapp/homes/networkandapi/TokenManager.kt
  9. 231
      app/src/main/java/com/example/dattingapp/permission/GallaryPermission.kt
  10. 331
      app/src/main/java/com/example/dattingapp/permission/LocationPermision.kt
  11. 274
      app/src/main/java/com/example/dattingapp/permission/NotificationPermission.kt
  12. 264
      app/src/main/java/com/example/dattingapp/permission/OtherAppPermission.kt
  13. 142
      app/src/main/java/com/example/dattingapp/permission/PermissionHelper.kt
  14. 240
      app/src/main/java/com/example/dattingapp/registration/RegistrationScreen.kt
  15. 15
      app/src/main/java/com/example/dattingapp/ui/theme/Color.kt

28
app/src/main/AndroidManifest.xml

@ -11,6 +11,7 @@
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<application
android:name=".MainApplication"
@ -35,33 +36,6 @@
</intent-filter>
</activity>
<activity
android:name=".permission.LocationPermision"
android:exported="false"
android:label="@string/title_activity_location_permission"
android:theme="@style/Theme.DattingAPP"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".permission.NotificationPermission"
android:exported="false"
android:label="@string/title_activity_notification_permission"
android:theme="@style/Theme.DattingAPP"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".permission.OtherAppPermission"
android:exported="false"
android:label="@string/title_activity_other_app_permission"
android:theme="@style/Theme.DattingAPP"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".permission.GallaryPermission"
android:exported="false"
android:label="@string/title_activity_gallery_permission"
android:theme="@style/Theme.DattingAPP"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".registration.RegistrationScreen"

623
app/src/main/java/com/example/dattingapp/ChatScreen.kt

@ -1,27 +1,616 @@
package com.example.dattingapp
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
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.filled.*
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.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import com.example.dattingapp.ui.theme.DattingAPPTheme
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
class ChatScreen : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
DattingAPPTheme {
// Data Models
data class ActiveSpark(
val name: String,
val isUser: Boolean = false
)
data class ChatMessage(
val id: Int,
val name: String,
val age: Int,
val time: String,
val isVerified: Boolean = false,
val matchPercentage: Int? = null,
val messageText: String? = null,
val isVoiceNote: Boolean = false,
val voiceDuration: String? = null,
val isPhoto: Boolean = false,
val photoText: String? = null,
val isAiBot: Boolean = false,
val aiTag: String? = null,
val unreadCount: Int = 0,
val isPinned: Boolean = false,
val isOnline: Boolean = false
)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ChatScreen(modifier: Modifier = Modifier) {
Scaffold(
topBar = {
Column(
modifier = Modifier
.fillMaxWidth()
.background(Color.White)
.statusBarsPadding()
) {
// Header
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
"Messages",
fontSize = 22.sp,
fontWeight = FontWeight.Bold
)
Surface(
color = Color(0xFFE91E63),
shape = RoundedCornerShape(12.dp)
) {
Text(
"3 new",
color = Color.White,
fontSize = 11.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(horizontal = 8.dp, vertical = 2.dp)
)
}
}
}
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
IconButton(
onClick = {},
modifier = Modifier
.size(36.dp)
.background(Color(0xFFF5F5F5), CircleShape)
) {
Icon(
imageVector = Icons.Default.Shield,
contentDescription = "Safety",
tint = Color.Gray,
modifier = Modifier.size(18.dp)
)
}
IconButton(
onClick = {},
modifier = Modifier
.size(36.dp)
.background(Color(0xFFF5F5F5), CircleShape)
) {
Icon(
imageVector = Icons.Default.Search,
contentDescription = "Search",
tint = Color.Gray,
modifier = Modifier.size(18.dp)
)
}
Box(
modifier = Modifier
.size(36.dp)
.clip(CircleShape)
.background(Color(0xFFCE93D8))
)
}
}
Spacer(modifier = Modifier.height(12.dp))
// Messages Title Bar
}
},
modifier = modifier.fillMaxSize()
) { innerPadding ->
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()
}
}

252
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<String>,
val imageUrl: String,
val hasUnread: Boolean = false
)
@Composable
fun ProfileGrid(profiles: List<Profile>, 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)
}

10
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 = {},

34
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()
setContent {
DattingAPPTheme {
// 2. Initialize PermissionHelper in onCreate() BEFORE setContent
permissionHelper = PermissionHelper(this)
val tokenManager = TokenManager.getInstance(this)
if (tokenManager.isLoggedIn()) {
// 1. User is logged in -> Navigate directly to Home
// User is logged in -> Navigate directly to Home and finish
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))
}
finish()
return
}else{
// Close MainActivity so it doesn't stay on the backstack
startActivity(Intent(this, LoginActivity::class.java))
finish()
}
setContent {
DattingAPPTheme {
// Render your main login/welcome UI screen here instead of finishing immediately
}
}
}
}

385
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()
}

105
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<PermissionHelper.PermissionType?>(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() {

2
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() {

231
app/src/main/java/com/example/dattingapp/permission/GallaryPermission.kt

@ -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 = {}
)
}
}

331
app/src/main/java/com/example/dattingapp/permission/LocationPermision.kt

@ -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 = {}
)
}
}

274
app/src/main/java/com/example/dattingapp/permission/NotificationPermission.kt

@ -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 = {}
)
}

264
app/src/main/java/com/example/dattingapp/permission/OtherAppPermission.kt

@ -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 = {}
)
}

142
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<Array<String>>
private lateinit var overlayLauncher: ActivityResultLauncher<Intent>
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<String> {
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
}
}

240
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<Long?>(null) }
var addressInput by rememberSaveable { mutableStateOf("") }
var selectedGender by rememberSaveable { mutableStateOf("") }
var selectedRealationStatus by remember { mutableStateOf<String?>(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

15
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)
Loading…
Cancel
Save