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. 42
      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.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<application <application
android:name=".MainApplication" android:name=".MainApplication"
@ -35,33 +36,6 @@
</intent-filter> </intent-filter>
</activity> </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 <activity
android:name=".registration.RegistrationScreen" android:name=".registration.RegistrationScreen"

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

@ -1,27 +1,616 @@
package com.example.dattingapp import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import android.os.Bundle import androidx.compose.foundation.border
import androidx.activity.ComponentActivity import androidx.compose.foundation.layout.*
import androidx.activity.compose.setContent import androidx.compose.foundation.lazy.LazyColumn
import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Scaffold import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier 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 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() { // Data Models
override fun onCreate(savedInstanceState: Bundle?) { data class ActiveSpark(
super.onCreate(savedInstanceState) val name: String,
enableEdgeToEdge() val isUser: Boolean = false
setContent { )
DattingAPPTheme {
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.homes.HomeActivity
import com.example.dattingapp.R import com.example.dattingapp.R
import com.example.dattingapp.homes.networkandapi.TokenManager import com.example.dattingapp.homes.networkandapi.TokenManager
import com.example.dattingapp.permission.PermissionHelper
import com.example.dattingapp.registration.LoginRequest import com.example.dattingapp.registration.LoginRequest
import com.example.dattingapp.registration.NetworkModule import com.example.dattingapp.registration.NetworkModule
import com.example.dattingapp.registration.RegistrationScreen import com.example.dattingapp.registration.RegistrationScreen
@ -44,9 +45,17 @@ import kotlinx.coroutines.launch
class LoginActivity : ComponentActivity() { class LoginActivity : ComponentActivity() {
private lateinit var permissionHelper: PermissionHelper
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
permissionHelper = PermissionHelper(this)
// 2. Call Notification Permission
permissionHelper.requestPermissions(PermissionHelper.PermissionType.NOTIFICATION) { isGranted ->
if (isGranted) { /* Handle granted */ }
}
enableEdgeToEdge() enableEdgeToEdge()
setContent { setContent {
DattingAPPTheme { DattingAPPTheme {
@ -66,7 +75,6 @@ class LoginActivity : ComponentActivity() {
} }
} }
} }
@Composable @Composable
fun LoginScreenContent( fun LoginScreenContent(
onLoginSuccess: () -> Unit = {}, onLoginSuccess: () -> Unit = {},

42
app/src/main/java/com/example/dattingapp/MainActivity.kt

@ -2,35 +2,49 @@ package com.example.dattingapp
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import com.example.dattingapp.Login.LoginActivity
import com.example.dattingapp.homes.HomeActivity import com.example.dattingapp.homes.HomeActivity
import com.example.dattingapp.homes.networkandapi.TokenManager 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 import com.example.dattingapp.ui.theme.DattingAPPTheme
class MainActivity : ComponentActivity() { 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) super.onCreate(savedInstanceState)
enableEdgeToEdge() 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 { setContent {
DattingAPPTheme { DattingAPPTheme {
val tokenManager = TokenManager.getInstance(this) // Render your main login/welcome UI screen here instead of finishing immediately
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()
} }
} }
} }
} }

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 package com.example.dattingapp.homes
import ChatScreen
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.widget.Toast
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge 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.Explore
import androidx.compose.material.icons.filled.Person import androidx.compose.material.icons.filled.Person
import androidx.compose.material.icons.filled.SwapHoriz import androidx.compose.material.icons.filled.SwapHoriz
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
@ -29,28 +33,97 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.example.dattingapp.ChatScreen
import com.example.dattingapp.homes.networkandapi.HomeNetworkModule import com.example.dattingapp.homes.networkandapi.HomeNetworkModule
import com.example.dattingapp.homes.networkandapi.MeetUiState import com.example.dattingapp.homes.networkandapi.MeetUiState
import com.example.dattingapp.homes.networkandapi.MeetUserProfile import com.example.dattingapp.homes.networkandapi.MeetUserProfile
import com.example.dattingapp.homes.networkandapi.MeetViewModel import com.example.dattingapp.homes.networkandapi.MeetViewModel
import com.example.dattingapp.homes.networkandapi.MyProfileUiState import com.example.dattingapp.homes.networkandapi.MyProfileUiState
import com.example.dattingapp.homes.networkandapi.MyProfileViewModel import com.example.dattingapp.homes.networkandapi.MyProfileViewModel
import com.example.dattingapp.permission.PermissionHelper
import com.example.dattingapp.ui.theme.DattingAPPTheme import com.example.dattingapp.ui.theme.DattingAPPTheme
import kotlinx.coroutines.delay
import kotlin.coroutines.cancellation.CancellationException import kotlin.coroutines.cancellation.CancellationException
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
class HomeActivity : ComponentActivity() { class HomeActivity : ComponentActivity() {
private lateinit var permissionHelper: PermissionHelper
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
permissionHelper = PermissionHelper(this)
enableEdgeToEdge() enableEdgeToEdge()
setContent { setContent {
DattingAPPTheme { 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() 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 @Composable
fun HomeScreen() { 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. // Checks local token presence, not server validity or expiration.
fun isLoggedIn(): Boolean { fun isLoggedIn(): Boolean {
return !getAccessToken().isNullOrBlank() return !getRefreshToken().isNullOrBlank()
} }
fun clearTokens() { 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.Date
import java.util.Locale import java.util.Locale
import androidx.compose.animation.core.* 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.Icon
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.draw.scale import androidx.compose.ui.draw.scale
@ -92,7 +97,7 @@ fun RegistrationFlowContainer(
val uiState by registrationViewModel.uiState.collectAsState() val uiState by registrationViewModel.uiState.collectAsState()
var currentStep by remember { mutableIntStateOf(1) } var currentStep by remember { mutableIntStateOf(1) }
val totalSteps = 6 val totalSteps = 7
BackHandler(enabled = currentStep > 1 && uiState !is RegistrationUiState.Loading) { BackHandler(enabled = currentStep > 1 && uiState !is RegistrationUiState.Loading) {
currentStep-- currentStep--
} }
@ -117,6 +122,7 @@ fun RegistrationFlowContainer(
var selectedBirthDateMillis by rememberSaveable { mutableStateOf<Long?>(null) } var selectedBirthDateMillis by rememberSaveable { mutableStateOf<Long?>(null) }
var addressInput by rememberSaveable { mutableStateOf("") } var addressInput by rememberSaveable { mutableStateOf("") }
var selectedGender by rememberSaveable { mutableStateOf("") } var selectedGender by rememberSaveable { mutableStateOf("") }
var selectedRealationStatus by remember { mutableStateOf<String?>(null) }
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
@ -217,6 +223,7 @@ fun RegistrationFlowContainer(
4 -> "Date of Birth" 4 -> "Date of Birth"
5 -> "Location" 5 -> "Location"
6 -> "Interested Gender" 6 -> "Interested Gender"
7-> "Relationship status"
else -> "" else -> ""
}, },
color = Color.Gray, color = Color.Gray,
@ -312,15 +319,20 @@ fun RegistrationFlowContainer(
addressText = addressInput, addressText = addressInput,
onAddressChange = { addressInput = it } onAddressChange = { addressInput = it }
) )
6 -> GenderCompose( 6 -> VibeCheckScreen(
selectedRealationStatus = selectedRealationStatus ?: "",
onRelationSelected = { selectedRealationStatus = it }
)
7 -> GenderCompose(
selectedGender = selectedGender, selectedGender = selectedGender,
onGenderSelected = { selectedGender = it } onGenderSelected = { selectedGender = it }
) )
else -> Text("Step $step") else -> Text("Step $step")
} }
} }
Spacer(modifier = Modifier.height(100.dp)) Spacer(modifier = Modifier.height(50.dp))
// 6. Action Button // 6. Action Button
Button( Button(
@ -374,6 +386,13 @@ fun RegistrationFlowContainer(
} else currentStep++ } else currentStep++
} }
6 -> { 6 -> {
if (selectedRealationStatus.isNullOrEmpty()) {
Toast.makeText(context, "Please select your vibe", Toast.LENGTH_SHORT).show()
} else {
currentStep++
}
}
7 -> {
if (selectedGender.isBlank()) { if (selectedGender.isBlank()) {
Toast.makeText(context, "Select gender interest", Toast.LENGTH_SHORT).show() Toast.makeText(context, "Select gender interest", Toast.LENGTH_SHORT).show()
return@Button return@Button
@ -1120,8 +1139,6 @@ data class GenderPreferenceOption(
val icon: ImageVector val icon: ImageVector
) )
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun BirthDayCompose( fun BirthDayCompose(
@ -1185,7 +1202,8 @@ fun BirthDayCompose(
// Input Card with Calendar Trigger Button // Input Card with Calendar Trigger Button
Card( Card(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth()
.clickable { showDatePickerDialog = true } ,
shape = RoundedCornerShape(20.dp), shape = RoundedCornerShape(20.dp),
colors = CardDefaults.cardColors(containerColor = Color.White), colors = CardDefaults.cardColors(containerColor = Color.White),
border = BorderStroke( border = BorderStroke(
@ -1204,14 +1222,17 @@ fun BirthDayCompose(
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(12.dp))
// Date Display Field & Select Button // Date Display Field & Select Button
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(InputBg, shape = RoundedCornerShape(12.dp)) .background(InputBg, shape = RoundedCornerShape(12.dp))
.clickable { showDatePickerDialog = true } // Added clickable modifier here
.padding(horizontal = 12.dp, vertical = 8.dp), .padding(horizontal = 12.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween horizontalArrangement = Arrangement.SpaceBetween
) { ){
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
@ -1233,31 +1254,7 @@ fun BirthDayCompose(
) )
) )
} }
// Open Calendar Button // 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 // Display Age Badge or Error Message
@ -1335,10 +1332,6 @@ fun BirthDayCompose(
} }
} }
@Composable @Composable
fun GenderCompose( fun GenderCompose(
selectedGender: String = "", 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) // 1. Email Tab Preview (Normal State)
@Preview(showBackground = true, name = "Step Two - Email Tab") @Preview(showBackground = true, name = "Step Two - Email Tab")
@Composable @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 LightBlueBg = Color(0xFFEEF5FF)
val LightPurpleBg = Color(0xFFF5EEFF) val LightPurpleBg = Color(0xFFF5EEFF)
val DarkOverlay = Color(0xCC212529) 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