You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
368 lines
14 KiB
368 lines
14 KiB
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
|
|
import androidx.compose.foundation.layout.Box
|
|
import androidx.compose.foundation.layout.padding
|
|
import androidx.compose.material.icons.Icons
|
|
import androidx.compose.material.icons.filled.Add
|
|
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
|
|
import androidx.compose.runtime.getValue
|
|
import androidx.compose.runtime.mutableIntStateOf
|
|
import androidx.compose.runtime.mutableStateOf
|
|
import androidx.compose.runtime.remember
|
|
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.homes.networkandapi.MeetUiState
|
|
import com.example.dattingapp.homes.networkandapi.MeetViewModel
|
|
import com.example.dattingapp.homes.networkandapi.ProfileViewModel
|
|
import com.example.dattingapp.homes.networkandapi.ProfileUiState
|
|
import com.example.dattingapp.permission.PermissionHelper
|
|
|
|
import com.example.dattingapp.ui.theme.DattingAPPTheme
|
|
import kotlinx.coroutines.delay
|
|
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 ->
|
|
if (!isGranted) {
|
|
Toast.makeText(
|
|
this@HomeActivity,
|
|
"Overlay Denied",
|
|
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()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@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() {
|
|
|
|
val appContext = LocalContext.current.applicationContext
|
|
|
|
|
|
var selectedItem by remember { mutableIntStateOf(0) }
|
|
|
|
Scaffold(
|
|
bottomBar = {
|
|
NavigationBar {
|
|
// =========================================
|
|
// MEET
|
|
// =========================================
|
|
|
|
NavigationBarItem(
|
|
selected = selectedItem == 0,
|
|
onClick = { selectedItem = 0 },
|
|
icon = {
|
|
Icon(
|
|
imageVector = Icons.Default.SwapHoriz,
|
|
contentDescription = "Meet"
|
|
)
|
|
},
|
|
label = {
|
|
Text("Meet")
|
|
}
|
|
)
|
|
// =========================================
|
|
// EXPLORE
|
|
// =========================================
|
|
NavigationBarItem(
|
|
selected = selectedItem == 1,
|
|
onClick = { selectedItem = 1 },
|
|
icon = {
|
|
Icon(
|
|
imageVector = Icons.Default.Explore,
|
|
contentDescription = "Explore"
|
|
)
|
|
},
|
|
|
|
label = { Text("Explore") }
|
|
)
|
|
|
|
|
|
// =========================================
|
|
// POST
|
|
// =========================================
|
|
|
|
NavigationBarItem(
|
|
selected = selectedItem == 2,
|
|
onClick = { selectedItem = 2 },
|
|
icon = { Icon(
|
|
imageVector = Icons.Default.Add,
|
|
contentDescription = "Post"
|
|
)
|
|
},
|
|
label = {
|
|
Text("Post")
|
|
}
|
|
)
|
|
// =========================================
|
|
// CHAT
|
|
// =========================================
|
|
NavigationBarItem(
|
|
selected = selectedItem == 3,
|
|
onClick = { selectedItem = 3 },
|
|
icon = {
|
|
Icon(
|
|
imageVector = Icons.Default.ChatBubbleOutline,
|
|
contentDescription = "Chat"
|
|
)
|
|
},
|
|
label = { Text("Chat") }
|
|
)
|
|
// =========================================
|
|
// PROFILE
|
|
// =========================================
|
|
NavigationBarItem(
|
|
selected = selectedItem == 4,
|
|
onClick = { selectedItem = 4 },
|
|
icon = {
|
|
Icon(
|
|
imageVector = Icons.Default.Person,
|
|
contentDescription = "Profile"
|
|
)
|
|
},
|
|
label = { Text("Profile") }
|
|
)
|
|
}
|
|
}
|
|
|
|
) { innerPadding ->
|
|
// =========================================
|
|
// CONTENT AREA
|
|
// =========================================
|
|
|
|
val context = LocalContext.current
|
|
|
|
// or via hiltViewModel() / factory
|
|
|
|
Box(modifier = Modifier.padding(innerPadding)) {
|
|
when (selectedItem) {
|
|
// =========================================
|
|
// MEET
|
|
// =========================================
|
|
0 -> {
|
|
// 1. Obtain instance of ViewModel and LocalContext
|
|
|
|
val viewModel: MeetViewModel = viewModel()
|
|
|
|
// 2. Collect state from ViewModel
|
|
val uiState by viewModel.meetUiState.collectAsState()
|
|
|
|
// 3. Trigger network call once when screen loads
|
|
LaunchedEffect(Unit) {
|
|
viewModel.meetUserResponse(context)
|
|
}
|
|
|
|
// 4. Map UI state to Composable parameters
|
|
when (val state = uiState) {
|
|
is MeetUiState.Loading, MeetUiState.Idle -> {
|
|
MeetDiscoveryScreen(
|
|
profiles = emptyList(),
|
|
isLoading = true,
|
|
errorMessage = null
|
|
)
|
|
}
|
|
is MeetUiState.Success -> {
|
|
MeetDiscoveryScreen(
|
|
profiles = state.response,
|
|
isLoading = false,
|
|
errorMessage = null
|
|
)
|
|
}
|
|
is MeetUiState.Error -> {
|
|
MeetDiscoveryScreen(
|
|
profiles = emptyList(),
|
|
isLoading = false,
|
|
errorMessage = state.message
|
|
)
|
|
}
|
|
}
|
|
}
|
|
// =========================================
|
|
// EXPLORE
|
|
// =========================================
|
|
1 -> {
|
|
VibeCheckHomeScreen()
|
|
}
|
|
// =========================================
|
|
// CREATE POST
|
|
// =========================================
|
|
2 -> {
|
|
CreateVibePostScreen()
|
|
}
|
|
// =========================================
|
|
// CHAT
|
|
// =========================================
|
|
3 -> {
|
|
ChatScreen()
|
|
}
|
|
// =========================================
|
|
// PROFILE
|
|
// =========================================
|
|
4 -> {
|
|
// 1. Obtain instance of ViewModel and LocalContext
|
|
val profileViewModel: ProfileViewModel = viewModel()
|
|
val context = LocalContext.current
|
|
|
|
// 2. Collect state from ViewModel
|
|
val uiState by profileViewModel.profileUiState.collectAsState()
|
|
|
|
// 3. Trigger network call once when screen loads
|
|
LaunchedEffect(Unit) {
|
|
profileViewModel.profileResponse(context)
|
|
}
|
|
|
|
// 4. Map UI state to Composable parameters
|
|
|
|
when (val state = uiState) {
|
|
is ProfileUiState.Loading, ProfileUiState.Idle -> {
|
|
MyProfileScreen(
|
|
profileResponse = null,
|
|
isLoading = true,
|
|
errorMessage = null,
|
|
// onRetry = { viewModel.meetUserResponse(context) }
|
|
)
|
|
}
|
|
is ProfileUiState.Success -> {
|
|
MyProfileScreen(
|
|
profileResponse = state.profileData, // or state.response depending on your data class naming
|
|
isLoading = false,
|
|
errorMessage = null,
|
|
)
|
|
}
|
|
is ProfileUiState.Error -> {
|
|
MyProfileScreen(
|
|
profileResponse = null,
|
|
isLoading = false,
|
|
errorMessage = state.message,
|
|
onRetry = { profileViewModel.profileResponse(context) }
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|