home screen

This commit is contained in:
sathwikcs
2024-10-19 11:46:03 +05:30
parent 39f43596ae
commit 4c2e12f075
2 changed files with 287 additions and 20 deletions

View File

@@ -8,13 +8,20 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize 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.padding
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
@@ -23,8 +30,11 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState import com.google.accompanist.permissions.rememberPermissionState
@@ -35,11 +45,15 @@ import `in`.sminnovations.attendanceapp.screens.home.ui.componets.RequestPermiss
import `in`.sminnovations.attendanceapp.screens.home.viewModel.HomeViewModel import `in`.sminnovations.attendanceapp.screens.home.viewModel.HomeViewModel
@OptIn(ExperimentalPermissionsApi::class) @OptIn(ExperimentalPermissionsApi::class, ExperimentalMaterial3Api::class)
@Composable @Composable
fun HomeScreen(viewModel: HomeViewModel = viewModel()) { fun HomeScreen(viewModel: HomeViewModel = hiltViewModel()) {
val isScanning by viewModel.isScanning.collectAsState() val isScanning by viewModel.isScanning.collectAsState()
val qrCodeValue by viewModel.qrCodeValue.collectAsState() val qrCodeValue by viewModel.qrCodeValue.collectAsState()
val checkInTime by viewModel.checkedIn.collectAsState()
val checkOutTime by viewModel.checkedOut.collectAsState()
val isCheckedIn by viewModel.isCheckedIn.collectAsState()
val isCheckedOut by viewModel.isCheckedOut.collectAsState()
val cameraPermissionState = rememberPermissionState(Manifest.permission.CAMERA) val cameraPermissionState = rememberPermissionState(Manifest.permission.CAMERA)
val locationPermissionState = rememberPermissionState(Manifest.permission.ACCESS_FINE_LOCATION) val locationPermissionState = rememberPermissionState(Manifest.permission.ACCESS_FINE_LOCATION)
@@ -78,20 +92,77 @@ fun HomeScreen(viewModel: HomeViewModel = viewModel()) {
} }
} }
LargeButton( OutlinedCard(modifier = Modifier
text = if (isScanning) "Close" else "Scan", .fillMaxWidth()
onClick = if (isScanning) { .fillMaxHeight(.47f)
{ viewModel.stopScanning() } .align(Alignment.BottomCenter)
} else { .padding(10.dp), onClick = { /*TODO*/ }
{ viewModel.startScanning() }
},
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = 24.dp)
)
if (isScanning) { ) {
BackHandler { viewModel.stopScanning() } Box(modifier = Modifier.fillMaxSize()) {
Column(
modifier = Modifier
.padding(20.dp)
.align(Alignment.TopCenter)
.fillMaxWidth()
) {
AnimatedVisibility(visible = isCheckedIn) {
Text(
text = "You already checked it Scanning Again will logout",
letterSpacing = 2.sp,
lineHeight = 40.sp,
fontSize = 30.sp,
color = MaterialTheme.colorScheme.error,
fontWeight = FontWeight.Bold
)
}
androidx.compose.animation.AnimatedVisibility(visible = !isCheckedIn) {
Text(
text = "Please Check In",
letterSpacing = 2.sp,
lineHeight = 40.sp,
fontSize = 30.sp,
color = Color.Green,
fontWeight = FontWeight.Bold
)
}
Column(Modifier.padding(15.dp)) {
androidx.compose.animation.AnimatedVisibility(visible = !isCheckedIn) {
Text(text = "Check in $checkInTime")
Spacer(modifier = Modifier.height(10.dp))
}
androidx.compose.animation.AnimatedVisibility(visible = isCheckedIn) {
Text(text = "Check Out$checkOutTime")
Spacer(modifier = Modifier.height(10.dp))
}
}
}
Column(Modifier.align(Alignment.BottomCenter)) {
LargeButton(text = if (isScanning) "Close" else "Scan",
onClick = if (isScanning) {
{ viewModel.stopScanning() }
} else {
{ viewModel.startScanning() }
},
modifier = Modifier
.padding(bottom = 24.dp))
if (isScanning) {
BackHandler { viewModel.stopScanning() }
}
LargeButton(
text = "Login", onClick = {
viewModel.loginNow()
}, modifier = Modifier
.padding(bottom = 24.dp)
)
if (isScanning) {
BackHandler { viewModel.stopScanning() }
}
}
}
} }
} }
} }

View File

@@ -1,25 +1,61 @@
package `in`.sminnovations.attendanceapp.screens.home.viewModel package `in`.sminnovations.attendanceapp.screens.home.viewModel
import android.util.Log
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.google.firebase.Timestamp
import com.google.firebase.firestore.FirebaseFirestore
import dagger.hilt.android.lifecycle.HiltViewModel
import `in`.sminnovations.attendanceapp.data.dataStore.EmployeeRepository
import `in`.sminnovations.attendanceapp.screens.home.data.CheckInCheckOutDataStore
import `in`.sminnovations.attendanceapp.screens.login.data.LoginDataStore
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.text.Format
import java.text.SimpleDateFormat
import java.time.LocalDate
import java.time.LocalTime
import java.util.Date
import java.util.Locale
import javax.inject.Inject
@HiltViewModel
class HomeViewModel @Inject constructor(
private val loginDataStore: LoginDataStore,
private val checkInCheckOutDataStore: CheckInCheckOutDataStore,
private val firebaseFirestore: FirebaseFirestore,
private val employeeRepository: EmployeeRepository
) : ViewModel() {
class HomeViewModel : ViewModel() {
private val _qrCodeValue = MutableStateFlow<String?>(null) private val _qrCodeValue = MutableStateFlow<String?>(null)
val qrCodeValue: StateFlow<String?> = _qrCodeValue.asStateFlow() val qrCodeValue: StateFlow<String?> = _qrCodeValue.asStateFlow()
private val _isScanning = MutableStateFlow(false) private val _isScanning = MutableStateFlow(false)
val isScanning: StateFlow<Boolean> = _isScanning.asStateFlow() val isScanning: StateFlow<Boolean> = _isScanning.asStateFlow()
private val _checkedIn = MutableStateFlow<String>("")
val checkedIn : StateFlow<String> = _checkedIn.asStateFlow()
private val _checkedOut = MutableStateFlow<String>("N /A ")
val checkedOut : StateFlow<String> = _checkedOut.asStateFlow()
private val _isCheckedIn = MutableStateFlow<Boolean>(false)
val isCheckedIn : StateFlow<Boolean> = _isCheckedIn.asStateFlow()
private val _isCheckedOut = MutableStateFlow<Boolean>(false)
val isCheckedOut : StateFlow<Boolean> = _isCheckedOut.asStateFlow()
fun startScanning() { fun startScanning() {
_isScanning.value = true _isScanning.value = true
} }
fun stopScanning() { fun stopScanning() {
_isScanning.value = false _isScanning.value = false
} }
@@ -30,9 +66,169 @@ class HomeViewModel : ViewModel() {
} }
} }
fun getEmployeeData(){ private fun formatTimestamp(timestamp: Timestamp): String {
val sdf = SimpleDateFormat("dd MMMM yyyy hh:mm:ss a", Locale.getDefault()) // Format with AM/PM
return sdf.format(timestamp.toDate())
}
init {
viewModelScope.launch {
checkInCheckOutDataStore.checkInId.collect { checkIn ->
checkInCheckOutDataStore.checkOutId.collect { checkOut ->
_checkedIn.value= checkIn
_checkedOut.value = checkOut
}
}
}
} }
private fun getIsCheckInCheckOut(){
viewModelScope.launch {
checkInCheckOutDataStore.isCheckedIn.collect { isCheckIn ->
checkInCheckOutDataStore.isCheckedOut.collect { isCheckOut ->
_isCheckedIn.value = isCheckIn
_isCheckedOut.value = isCheckOut
}
}
}
}
private fun getFormattedDate(): String {
val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault())
return dateFormat.format(Date())
}
fun loginNow() {
viewModelScope.launch {
checkInCheckOutDataStore.checkInDate.collect { checkOutDate ->
loginDataStore.loginId.collect { _ ->
firebaseFirestore.collection("qr_key").whereEqualTo("id", getFormattedDate())
.get().addOnSuccessListener { querySnapshot ->
if (!querySnapshot.isEmpty) {
for (document in querySnapshot) {
if (qrCodeValue.value == document.getString("key")) {
viewModelScope.launch {
if (checkOutDate != LocalDate.now().toString() || checkOutDate =="") {
putCheckInAttendance("")
} else {
putCheckOutAttendance()
}
}
} else {
Log.d("loginNow", "Invalid QR code scanned")
}
}
} else {
Log.d("loginNow", "No matching QR key found for today's date")
}
}.addOnFailureListener { exception ->
Log.e("Firestore", "Error fetching QR key: ", exception)
}
}
}
}
}
private fun putCheckInAttendance(location: String) {
viewModelScope.launch {
loginDataStore.loginId.collect { id ->
val currentDate = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(Date())
val attendanceRef = firebaseFirestore.collection("attendance_$id").document(currentDate)
attendanceRef.get().addOnSuccessListener { document ->
if (!document.exists()) {
val checkInData = hashMapOf(
"Status" to false,
"checkIn" to Timestamp.now(),
"location" to location
)
attendanceRef.set(checkInData).addOnSuccessListener {
// Save the check-in data to a local datastore if needed
viewModelScope.launch {
checkInCheckOutDataStore.saveLoginData(
formatTimestamp(Timestamp.now()),
"Not yet Done"
)
checkInCheckOutDataStore.saveLoginDate(LocalDate.now().toString())
checkInCheckOutDataStore.saveIsLogIn(true)
}
Log.d("Firestore", "Check-in successful")
_isCheckedIn.value = true
}.addOnFailureListener { e ->
Log.e("Firestore", "Error adding check-in", e)
}
} else {
// Document exists, check the checkOut field
val checkOut = document.getTimestamp("checkout")
if (checkOut == null) {
Log.d(
"Firestore",
"Check-in already exists for today. Cannot check in again."
)
} else {
Log.d("Firestore", "Attendance already completed for today.")
}
}
}.addOnFailureListener { exception ->
Log.e("Firestore", "Error fetching document: ", exception)
}
}
}
}
fun putCheckOutAttendance() {
viewModelScope.launch {
loginDataStore.loginId.collect { id ->
val currentDate = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(Date())
val attendanceRef =
firebaseFirestore.collection("attendance_$id").document(currentDate)
attendanceRef.get().addOnSuccessListener { document ->
if (document.exists()) {
val checkIn = document.getTimestamp("checkIn")
val checkOut = document.getTimestamp("checkout")
if (checkIn != null && checkOut == null) {
val checkOutData = hashMapOf(
"checkout" to Timestamp.now(), "Status" to true
) as Map<String, Any>
attendanceRef.update(checkOutData).addOnSuccessListener {
viewModelScope.launch {
checkInCheckOutDataStore.saveLoginData(checkedIn.value,formatTimestamp(Timestamp.now()))
checkInCheckOutDataStore.saveIsLogIn(false)
}
Log.d("Firestore", "Check-out successful")
}.addOnFailureListener { e ->
Log.e("Firestore", "Error adding check-out", e)
}
} else if (checkOut != null) {
Log.d("Firestore", "Already checked out for today.")
} else {
Log.d("Firestore", "Cannot check out without checking in.")
}
} else {
Log.d(
"Firestore", "No attendance found for today. Please check in first."
)
}
}.addOnFailureListener { exception ->
Log.e("Firestore", "Error fetching document: ", exception)
}
}
}
}
} }