removed the unnecessary things

This commit is contained in:
sathwikcs
2024-10-23 23:18:29 +05:30
parent d1b31bc645
commit 10b06b2019
21 changed files with 251 additions and 1196 deletions

View File

@@ -1,41 +0,0 @@
package `in`.sminnovations.attendanceapp
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.runtime.Composable
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import `in`.sminnovations.attendanceapp.screens.login.ui.LoginScreen
@Composable
fun AppNavigation() {
val navController = rememberNavController()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
NavigationHost(navController = navController)
}
}
@RequiresApi(Build.VERSION_CODES.O_MR1)
@Composable
fun NavigationHost(navController: NavHostController) {
NavHost(navController = navController, startDestination = "login") {
composable("login") {
LoginScreen(
loginViewModel = hiltViewModel(),
onLoginSuccess = {
navController.navigate("main") {
popUpTo("login") { inclusive = true }
}
}
)
}
composable("main") {
MainScreen(navController)
}
}
}

View File

@@ -1,14 +0,0 @@
package `in`.sminnovations.attendanceapp.data.dataStore
data class Employee(
val androidID: String = "",
val dateOfJoining: String = "",
val dateOfLeaving: String = "",
val designation: String = "Android Developer",
val employeeStatus: Boolean = true,
val id: String = "",
val name: String = "",
val password: String = "",
val photo: String = "",
val dateOfBirth: String = ""
)

View File

@@ -1,17 +0,0 @@
package `in`.sminnovations.attendanceapp.data.dataStore
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
object EmployeePreferencesKeys {
val ANDROID_ID = stringPreferencesKey("android_id")
val DATE_OF_JOINING = stringPreferencesKey("date_of_joining")
val DATE_OF_LEAVING = stringPreferencesKey("date_of_leaving")
val DESIGNATION = stringPreferencesKey("designation")
val EMPLOYEE_STATUS = booleanPreferencesKey("employee_status")
val ID = stringPreferencesKey("id")
val NAME = stringPreferencesKey("name")
val PASSWORD = stringPreferencesKey("password")
val PHOTO = stringPreferencesKey("photo")
val DATE_OF_BIRTH = stringPreferencesKey("date_of_birth")
}

View File

@@ -1,83 +0,0 @@
package `in`.sminnovations.attendanceapp.data.dataStore
import android.content.Context
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.emptyPreferences
import androidx.datastore.preferences.preferencesDataStore
import dagger.hilt.android.qualifiers.ApplicationContext
import `in`.sminnovations.attendanceapp.screens.settings.data.EmployeeDataSettings
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
import java.io.IOException
import javax.inject.Inject
import javax.inject.Singleton
val Context.employeeDataStore by preferencesDataStore("employee_data")
@Singleton
class EmployeeRepository @Inject constructor(
@ApplicationContext private val context: Context
) {
suspend fun saveEmployeeData(employee: Employee) {
context.employeeDataStore.edit { preferences ->
preferences[EmployeePreferencesKeys.ANDROID_ID] = employee.androidID
preferences[EmployeePreferencesKeys.DATE_OF_JOINING] = employee.dateOfJoining
preferences[EmployeePreferencesKeys.DATE_OF_LEAVING] = employee.dateOfLeaving
preferences[EmployeePreferencesKeys.DESIGNATION] = employee.designation
preferences[EmployeePreferencesKeys.EMPLOYEE_STATUS] = employee.employeeStatus
preferences[EmployeePreferencesKeys.ID] = employee.id
preferences[EmployeePreferencesKeys.NAME] = employee.name
preferences[EmployeePreferencesKeys.PASSWORD] = employee.password
preferences[EmployeePreferencesKeys.PHOTO] = employee.photo
preferences[EmployeePreferencesKeys.DATE_OF_BIRTH] = employee.dateOfBirth
}
}
fun getEmployeeData(): Flow<Employee> {
return context.employeeDataStore.data
.catch { exception ->
// If an error occurs, emit an empty preferences object
if (exception is IOException) {
emit(emptyPreferences())
} else {
throw exception
}
}
.map { preferences ->
Employee(
androidID = preferences[EmployeePreferencesKeys.ANDROID_ID] ?: "",
dateOfJoining = preferences[EmployeePreferencesKeys.DATE_OF_JOINING] ?: "",
dateOfLeaving = preferences[EmployeePreferencesKeys.DATE_OF_LEAVING] ?: "",
designation = preferences[EmployeePreferencesKeys.DESIGNATION] ?: "Android Developer",
employeeStatus = preferences[EmployeePreferencesKeys.EMPLOYEE_STATUS] ?: true,
id = preferences[EmployeePreferencesKeys.ID] ?: "",
name = preferences[EmployeePreferencesKeys.NAME] ?: "",
password = preferences[EmployeePreferencesKeys.PASSWORD] ?: "",
photo = preferences[EmployeePreferencesKeys.PHOTO] ?: "",
dateOfBirth = preferences[EmployeePreferencesKeys.DATE_OF_BIRTH] ?: ""
)
}
}
fun getEmployeeDataSettings(): Flow<EmployeeDataSettings> {
return context.employeeDataStore.data
.catch { exception ->
if (exception is IOException) {
emit(emptyPreferences())
} else {
throw exception
}
}
.map { preferences ->
EmployeeDataSettings(
name = preferences[EmployeePreferencesKeys.NAME] ?: "",
id = preferences[EmployeePreferencesKeys.ID] ?: "",
designation = preferences[EmployeePreferencesKeys.DESIGNATION] ?: ""
)
}
}
}

View File

@@ -1,73 +0,0 @@
package `in`.sminnovations.attendanceapp.screens.history.components
import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
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.sp
import `in`.sminnovations.attendanceapp.screens.history.data.AttendanceData
@Composable
fun EnhancedAttendanceCard(attendance: AttendanceData) {
var isExpanded by remember { mutableStateOf(false) }
Card(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp, horizontal = 16.dp)
.animateContentSize(), // Animate the size change for a smooth expand/collapse
shape = RoundedCornerShape(12.dp),
elevation = CardDefaults.cardElevation(6.dp)
) {
Column(
modifier = Modifier
.background(MaterialTheme.colorScheme.primaryContainer)
.padding(16.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
Text(
text = attendance.date,
fontWeight = FontWeight.Bold,
fontSize = 18.sp,
color = MaterialTheme.colorScheme.onPrimaryContainer,
modifier = Modifier.weight(1f)
)
IconButton(
onClick = { isExpanded = !isExpanded }
) {
Icon(
imageVector = Icons.Default.ArrowDropDown,
contentDescription = "Expand or Collapse",
tint = MaterialTheme.colorScheme.onPrimaryContainer
)
}
}
if (isExpanded) {
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "Check In: ${attendance.checkInTime ?: "N/A"}",
color = MaterialTheme.colorScheme.onPrimaryContainer
)
Text(
text = "Check Out: ${attendance.checkOutTime ?: "N/A"}",
color = MaterialTheme.colorScheme.onPrimaryContainer
)
}
}
}
}

View File

@@ -1,9 +0,0 @@
package `in`.sminnovations.attendanceapp.screens.history.data
import com.google.firebase.Timestamp
data class AttendanceData(
val date: String,
val checkInTime: String?,
val checkOutTime: String?
)

View File

@@ -1,62 +0,0 @@
package `in`.sminnovations.attendanceapp.screens.history.ui
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import `in`.sminnovations.attendanceapp.screens.history.components.EnhancedAttendanceCard
import `in`.sminnovations.attendanceapp.screens.history.viewModel.HistoryViewModel
import `in`.sminnovations.attendanceapp.screens.login.viewModel.LoginViewModel
@Composable
fun HistoryScreen(
historyViewModel: HistoryViewModel = hiltViewModel(),
) {
val attendanceData = historyViewModel.listOfAttendanceDates.collectAsState().value
Column(modifier = Modifier.fillMaxSize()) {
Row (
Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
){
Text(
text = "Your Attendance History",
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(16.dp),
color = MaterialTheme.colorScheme.primary
)
Button(onClick = {historyViewModel.refresh() }) {
Text(text = "Refresh")
}
}
LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding(vertical = 8.dp)
) {
items(attendanceData) { attendance ->
EnhancedAttendanceCard(attendance = attendance)
}
}
}
}

View File

@@ -1,97 +0,0 @@
package `in`.sminnovations.attendanceapp.screens.history.viewModel
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.firebase.Timestamp
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.toObject
import dagger.hilt.android.lifecycle.HiltViewModel
import `in`.sminnovations.attendanceapp.screens.history.data.AttendanceData
import `in`.sminnovations.attendanceapp.screens.login.data.LoginDataStore
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import javax.inject.Inject
@HiltViewModel
class HistoryViewModel @Inject constructor(
private val loginDataStore: LoginDataStore,
private val firebaseFirestore: FirebaseFirestore,
) : ViewModel() {
private val _isLoggedIn = MutableStateFlow(false)
val isLoggedIn = _isLoggedIn.asStateFlow()
private val _listOfAttendanceDates = MutableStateFlow<List<AttendanceData>>(emptyList())
val listOfAttendanceDates = _listOfAttendanceDates.asStateFlow()
init {
viewModelScope.launch {
getAttendanceData()
}
}
fun refresh() {
viewModelScope.launch {
getAttendanceData()
}
}
private fun getAttendanceData() {
viewModelScope.launch {
loginDataStore.loginId.collect { id ->
firebaseFirestore.collection("attendance_$id").get()
.addOnSuccessListener { result ->
viewModelScope.launch {
val attendanceList = result.documents.mapNotNull { document ->
val date = document.id // Assuming the document ID is the date
val checkInTimestamp = document.getString("checkIn") ?: "NA"
val checkOutTimestamp = document.getString("checkOut") ?: "NA"
val checkIn = formatTimestamp(checkInTimestamp)
val checkOut = formatTimestamp(checkOutTimestamp)
AttendanceData(date, checkIn, checkOut)
}
_listOfAttendanceDates.value = attendanceList
}
}
.addOnFailureListener { exception ->
Log.e("Firestore", "Error getting documents: ", exception)
viewModelScope.launch {
_listOfAttendanceDates.value = emptyList()
}
}
}
}
}
private fun formatTimestamp(timestamp: Any): String {
val sdf = SimpleDateFormat("dd MMMM yyyy hh:mm a", Locale.getDefault())
return if (timestamp is Timestamp) {
sdf.format(timestamp.toDate())
} else {
timestamp.toString()
}
}
}

View File

@@ -1,74 +0,0 @@
package `in`.sminnovations.attendanceapp.screens.home.data
import android.content.Context
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import javax.inject.Inject
import javax.inject.Singleton
private const val DATASTORE_NAME = "check_in_check_out_prefs"
private val Context.dataStore by preferencesDataStore(name = DATASTORE_NAME)
@Singleton
class CheckInCheckOutDataStore @Inject constructor(@ApplicationContext context: Context) {
private val dataStore = context.dataStore
private val CHECK_IN_KEY = stringPreferencesKey("check_in_id")
private val CHECK_OUT_KEY = stringPreferencesKey("check_out_id")
private val CHECK_IN_Date = stringPreferencesKey("check_in_date_id")
private val IS_CHECK_IN = booleanPreferencesKey("is_checked_in_id")
private val IS_CHECK_OUT = booleanPreferencesKey("is_checked_in_id")
val checkInId: Flow<String> = dataStore.data.map { preferences ->
preferences[CHECK_IN_KEY] ?: ""
}
val checkOutId: Flow<String> = dataStore.data.map { preferences ->
preferences[CHECK_OUT_KEY] ?: ""
}
val checkInDate: Flow<String> = dataStore.data.map { preferences ->
preferences[CHECK_IN_Date] ?: ""
}
suspend fun saveLoginData(checkOut: String) {
dataStore.edit { preferences ->
preferences[CHECK_OUT_KEY] = checkOut
}
}
suspend fun saveLoginDate(checkDate: String,checkInTime: String) {
dataStore.edit { preferences ->
preferences[CHECK_IN_Date] = checkDate
preferences[CHECK_IN_KEY] = checkInTime
}
}
suspend fun saveIsLogIn(isCheckIn: Boolean) {
dataStore.edit { preferences ->
preferences[IS_CHECK_IN] = isCheckIn
}
}
suspend fun clearLoginData() {
dataStore.edit { preferences ->
preferences.remove(CHECK_IN_Date)
preferences.remove(IS_CHECK_OUT)
preferences.remove(IS_CHECK_IN)
preferences.remove(CHECK_IN_KEY)
preferences.remove(CHECK_OUT_KEY)
}
}
}

View File

@@ -1,2 +0,0 @@
package `in`.sminnovations.attendanceapp.screens.home.ui.componets

View File

@@ -1,37 +0,0 @@
package `in`.sminnovations.attendanceapp.screens.home.ui.componets
import android.widget.Toast
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.PermissionState
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.shouldShowRationale
@Composable
fun DefaultScreen(
qrCodeValue: String?,
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
qrCodeValue?.let {
Text(text = "Scanned Value: $it", modifier = Modifier.padding(16.dp))
}
}
}

View File

@@ -8,14 +8,17 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
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.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
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.wrapContentSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.CircularProgressIndicator
@@ -26,6 +29,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
@@ -40,7 +44,6 @@ import androidx.hilt.navigation.compose.hiltViewModel
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
import `in`.sminnovations.attendanceapp.screens.home.ui.componets.DefaultScreen
import `in`.sminnovations.attendanceapp.screens.home.ui.componets.LargeButton
import `in`.sminnovations.attendanceapp.screens.home.ui.componets.QRCodeScannerScreen
import `in`.sminnovations.attendanceapp.screens.home.ui.componets.RequestPermissions
@@ -51,19 +54,18 @@ import `in`.sminnovations.attendanceapp.screens.home.viewModel.HomeViewModel
fun HomeScreen(viewModel: HomeViewModel = hiltViewModel()) {
val isScanning by viewModel.isScanning.collectAsState()
val qrCodeValue by viewModel.qrCodeValue.collectAsState()
val checkInTime by viewModel.checkedIn.collectAsState()
val checkOutTime by viewModel.checkedOut.collectAsState()
val userName by viewModel.userName.collectAsState()
val isLoading by viewModel.isLoading.collectAsState()
val isCheckedIn by viewModel.isCheckedIn.collectAsState()
val isCheckedOut by viewModel.isCheckedOut.collectAsState()
val isLoading by viewModel.isLoading.collectAsState()
val errorMessage by viewModel.errorMessage.collectAsState()
val cameraPermissionState = rememberPermissionState(Manifest.permission.CAMERA)
val locationPermissionState = rememberPermissionState(Manifest.permission.ACCESS_FINE_LOCATION)
val allPermissionsGranted = remember {
derivedStateOf {
cameraPermissionState.status.isGranted && locationPermissionState.status.isGranted
cameraPermissionState.status.isGranted
}
}
@@ -71,11 +73,8 @@ fun HomeScreen(viewModel: HomeViewModel = hiltViewModel()) {
if (!allPermissionsGranted.value) {
RequestPermissions(
cameraPermissionState = cameraPermissionState,
locationPermissionState = locationPermissionState
)
} else {
DefaultScreen(qrCodeValue = qrCodeValue)
AnimatedVisibility(
visible = isScanning,
enter = expandVertically(expandFrom = Alignment.Bottom) + fadeIn(),
@@ -93,8 +92,80 @@ fun HomeScreen(viewModel: HomeViewModel = hiltViewModel()) {
}
}
}
AnimatedVisibility(
visible = !isScanning && qrCodeValue == "" && isCheckedIn && !isCheckedOut,
enter = expandVertically(expandFrom = Alignment.Bottom) + fadeIn(),
exit = shrinkVertically(shrinkTowards = Alignment.Bottom) + fadeOut()
) {
Box(
contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()
) {
Column {
OutlinedCard {
Text(
text = "Checked In as",
letterSpacing = 2.sp,
lineHeight = 40.sp,
fontSize = 30.sp,
color = Color.Green,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(10.dp, 5.dp)
)
}
Spacer(modifier = Modifier.height(10.dp))
Text(
text = " $userName",
letterSpacing = 2.sp,
lineHeight = 40.sp,
fontSize = 30.sp,
fontWeight = FontWeight.Bold
)
}
}
}
AnimatedVisibility(
visible = !isScanning && qrCodeValue == "" && !isCheckedIn && isCheckedOut,
enter = expandVertically(expandFrom = Alignment.Bottom) + fadeIn(),
exit = shrinkVertically(shrinkTowards = Alignment.Bottom) + fadeOut()
) {
Box(
contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()
) {
Column {
OutlinedCard {
Text(
text = "Checked Out as",
letterSpacing = 2.sp,
lineHeight = 40.sp,
fontSize = 30.sp,
color = Color.Green,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(10.dp, 5.dp)
)
}
Spacer(modifier = Modifier.height(10.dp))
Text(
text = " $userName",
letterSpacing = 2.sp,
lineHeight = 40.sp,
fontSize = 30.sp,
fontWeight = FontWeight.Bold
)
}
}
}
}
// Loading Indicator
if (isLoading) {
CircularProgressIndicator(
@@ -102,42 +173,22 @@ fun HomeScreen(viewModel: HomeViewModel = hiltViewModel()) {
)
}
// Display Error Message
errorMessage?.let { message ->
Box(
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
.padding(16.dp)
) {
Text(
text = message,
color = MaterialTheme.colorScheme.error,
fontWeight = FontWeight.Bold,
modifier = Modifier
.background(Color(0xFFFFCDD2)) // Light red background for error
.padding(8.dp)
.align(Alignment.Center)
)
}
}
OutlinedCard(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(.47f)
.align(Alignment.BottomCenter)
.padding(10.dp),
onClick = { }
) {
OutlinedCard(modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(.4f)
.align(Alignment.BottomCenter)
.padding(10.dp), onClick = { }) {
Box(modifier = Modifier.fillMaxSize()) {
Column(
modifier = Modifier
.padding(20.dp)
.align(Alignment.TopCenter)
.fillMaxWidth()
) {
errorMessage?.let { message ->
errorMessage?.let { message ->
OutlinedCard(
modifier = Modifier
.wrapContentSize()
.align(Alignment.TopCenter)
.padding(16.dp)
) {
Text(
text = message,
color = MaterialTheme.colorScheme.error,
@@ -145,67 +196,32 @@ fun HomeScreen(viewModel: HomeViewModel = hiltViewModel()) {
modifier = Modifier
.background(Color(0xFFFFCDD2)) // Light red background for error
.padding(8.dp)
)
}
AnimatedVisibility(visible = isCheckedIn && !isCheckedOut) {
Text(
text = "You already checked in. Scanning again will Check out.",
letterSpacing = 2.sp,
lineHeight = 40.sp,
fontSize = 30.sp,
color = MaterialTheme.colorScheme.error,
fontWeight = FontWeight.Bold
)
}
AnimatedVisibility(visible = !isCheckedIn && !isCheckedOut) {
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)) {
AnimatedVisibility(visible = isCheckedIn || isCheckedOut) {
Text(text = "Check-in: $checkInTime")
Spacer(modifier = Modifier.height(10.dp))
}
AnimatedVisibility(visible = (isCheckedIn && isCheckedOut) || isCheckedOut ) {
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() }
Row(
Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
LargeButton(text = if (isScanning) "Close Scanner" else "Open Scanner",
onClick = if (isScanning) {
{
viewModel.stopScanning()
}
} else {
{
viewModel.startScanning()
}
},
modifier = Modifier.padding(bottom = 24.dp))
}
AnimatedVisibility(visible = !isCheckedIn) {
LargeButton(
text = "Check In",
onClick = { viewModel.loginNow() },
modifier = Modifier.padding(bottom = 24.dp)
)
}
AnimatedVisibility(visible = isCheckedIn ) {
LargeButton(
text = "Check Out",
onClick = { viewModel.loginNow() },
modifier = Modifier.padding(bottom = 24.dp)
)
LaunchedEffect(qrCodeValue) {
viewModel.login()
}
if (isScanning) {
BackHandler { viewModel.stopScanning() }

View File

@@ -4,25 +4,21 @@ package `in`.sminnovations.attendanceapp.screens.home.viewModel
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.compose.viewModel
import com.google.firebase.Timestamp
import com.google.firebase.firestore.FirebaseFirestore
import dagger.hilt.android.lifecycle.HiltViewModel
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.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.time.LocalDate
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,
) : ViewModel() {
@@ -32,11 +28,9 @@ class HomeViewModel @Inject constructor(
private val _isScanning = MutableStateFlow(false)
val isScanning: StateFlow<Boolean> = _isScanning.asStateFlow()
private val _checkedIn = MutableStateFlow("")
val checkedIn: StateFlow<String> = _checkedIn.asStateFlow()
private val _userName = MutableStateFlow<String?>(null)
val userName: StateFlow<String?> = _userName.asStateFlow()
private val _checkedOut = MutableStateFlow("N/A")
val checkedOut: StateFlow<String> = _checkedOut.asStateFlow()
private val _isCheckedIn = MutableStateFlow(false)
val isCheckedIn: StateFlow<Boolean> = _isCheckedIn.asStateFlow()
@@ -50,6 +44,7 @@ class HomeViewModel @Inject constructor(
private val _isLoading = MutableStateFlow(false)
val isLoading: StateFlow<Boolean> = _isLoading.asStateFlow()
private fun postErrorMessage(message: String) {
viewModelScope.launch {
_errorMessage.emit(message)
@@ -58,10 +53,17 @@ class HomeViewModel @Inject constructor(
fun startScanning() {
_isScanning.value = true
_errorMessage.value = null
_isCheckedIn.value = false
_isCheckedOut.value = false
_userName.value =""
}
fun stopScanning() {
_isScanning.value = false
_errorMessage.value = null
_isCheckedIn.value = false
_isCheckedOut.value = false
}
fun setQRCodeValue(value: String) {
@@ -79,175 +81,159 @@ class HomeViewModel @Inject constructor(
init {
viewModelScope.launch {
getCheckInChekout()
startScanning()
}
}
private fun getCheckInChekout() {
viewModelScope.launch {
checkInCheckOutDataStore.checkInId.collect { checkIn ->
_checkedIn.value = checkIn
}
}
viewModelScope.launch {
checkInCheckOutDataStore.checkOutId.collect { checkOut ->
_checkedOut.value = checkOut
}
}
viewModelScope.launch {
checkInCheckOutDataStore.checkInDate.collect {date ->
if (date == LocalDate.now().toString()) {
_isCheckedIn.value = true
}
}
}
}
private fun getFormattedDate(): String {
val dateFormat = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault())
return dateFormat.format(Date())
}
fun loginNow() {
private fun putCheckInAttendance(id: String) {
viewModelScope.launch {
_isLoading.value = true
checkInCheckOutDataStore.checkInDate.collect { checkOutDate ->
loginDataStore.loginId.collect { _ ->
firebaseFirestore.collection("qr_key").whereEqualTo("id", getFormattedDate())
.get().addOnSuccessListener { querySnapshot ->
_isLoading.value = false
if (!querySnapshot.isEmpty) {
for (document in querySnapshot) {
if (qrCodeValue.value == document.getString("key")) {
viewModelScope.launch {
if (checkOutDate != LocalDate.now().toString() || checkOutDate == ""
) {
putCheckInAttendance("")
} else {
viewModelScope.launch {
_isCheckedIn.value = true
}
val currentDate = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(Date())
val attendanceRef = firebaseFirestore.collection("attendance_$id").document(currentDate)
putCheckOutAttendance()
}
}
} else {
postErrorMessage("Invalid QR code scanned")
}
}
} else {
postErrorMessage("No matching QR key found for today's date")
}
}.addOnFailureListener { exception ->
_isLoading.value = false
postErrorMessage("Error fetching QR key: ${exception.message}")
}
}
}
}
}
attendanceRef.get().addOnSuccessListener { document ->
_isLoading.value = false
if (!document.exists()) {
val checkInData = hashMapOf(
"DayCompleted" to false,
"checkIn" to formatTimestamp(Timestamp.now()),
"checkOut" to "NA"
)
private fun putCheckInAttendance(location: String) {
viewModelScope.launch {
_isLoading.value = true
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 ->
_isLoading.value = false
if (!document.exists()) {
val checkInData = hashMapOf(
"Status" to false,
"checkIn" to formatTimestamp(Timestamp.now()),
"location" to location,
"checkOut" to "NA"
)
attendanceRef.set(checkInData).addOnSuccessListener {
viewModelScope.launch {
checkInCheckOutDataStore.saveLoginDate(
checkDate = LocalDate.now().toString(),
checkInTime = formatTimestamp(Timestamp.now())
)
}
Log.d("Firestore", "Check-in successful")
viewModelScope.launch {
_isCheckedIn.value = true
}
}.addOnFailureListener { e ->
postErrorMessage("Error adding check-in: ${e.message}")
}
} else {
postErrorMessage("Check-in already exists for today. Cannot check in again.")
attendanceRef.set(checkInData).addOnSuccessListener {
Log.d("Firestore", "Check-in successful")
viewModelScope.launch {
_isCheckedIn.value = true
_isCheckedIn.value =true
}
}.addOnFailureListener { e ->
postErrorMessage("Error adding check-in: ${e.message}")
}
}.addOnFailureListener { exception ->
_isLoading.value = false
postErrorMessage("Error fetching document: ${exception.message}")
} else {
putCheckOutAttendance(id)
}
}.addOnFailureListener { exception ->
_isLoading.value = false
postErrorMessage("Error fetching document: ${exception.message}")
}
}
}
private fun putCheckOutAttendance() {
private fun putCheckOutAttendance(id: String) {
viewModelScope.launch {
_isLoading.value = true
loginDataStore.loginId.collect { id ->
val currentDate = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(Date())
val attendanceRef =
firebaseFirestore.collection("attendance_$id").document(currentDate)
val currentDate = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(Date())
val attendanceRef = firebaseFirestore.collection("attendance_$id").document(currentDate)
attendanceRef.get().addOnSuccessListener { document ->
_isLoading.value = false
if (document.exists()) {
val checkIn = document.getString("checkIn")
val checkOut = document.getString("checkOut")
attendanceRef.get().addOnSuccessListener { document ->
_isLoading.value = false
if (document.exists()) {
val checkIn = document.getString("checkIn")
val checkOut = document.getString("checkOut")
if (checkIn != null && checkOut == "NA") {
val checkOutData = hashMapOf(
"checkOut" to formatTimestamp(Timestamp.now()), "Status" to true
) as Map<String, Any>
if (checkIn != null && checkOut == "NA") {
val checkOutData = hashMapOf(
"checkOut" to formatTimestamp(Timestamp.now()), "DayCompleted" to true
) as Map<String, Any>
attendanceRef.update(checkOutData).addOnSuccessListener {
viewModelScope.launch {
checkInCheckOutDataStore.saveLoginData(
checkOut = formatTimestamp(
Timestamp.now()
)
)
checkInCheckOutDataStore.saveIsLogIn(false)
}
Log.d("Firestore", "Check-out successful")
}.addOnFailureListener { e ->
postErrorMessage("Error adding check-out: ${e.message}")
}
} else if (checkOut != "NA") {
postErrorMessage("Already checked out for today.")
attendanceRef.update(checkOutData).addOnSuccessListener {
viewModelScope.launch {
_isCheckedOut.value = true
_isCheckedOut.value =true
}
Log.d("Firestore", "Check-out successful")
}.addOnFailureListener { e ->
postErrorMessage("Error adding check-out: ${e.message}")
}
} else if (checkOut != "NA") {
postErrorMessage("Already checked out for today.")
} else {
putCheckInAttendance(id)
}
} else {
postErrorMessage("No attendance found for today. Please check in first.")
}
}.addOnFailureListener { exception ->
_isLoading.value = false
postErrorMessage("Error fetching document: ${exception.message}")
}
}
}
fun login(userId: String? = qrCodeValue.value) {
if (qrCodeValue.value != "" && userId != null) { // don't simplify it
_isLoading.value = true
viewModelScope.launch {
_errorMessage.emit(null)
firebaseFirestore.collection("employees").whereEqualTo("Id", userId).get()
.addOnSuccessListener {
if (!it.isEmpty) {
for (doc in it) {
if (true == doc.getBoolean("EmployeeStatus")) {
viewModelScope.launch {
_isLoading.value = false
_userName.value = doc.getString("Name")
putQRvalueEmpty()
putCheckInAttendance(userId)
}
} else {
postErrorMessage("ID has been expired }")
}
}
} else {
postErrorMessage("Cannot check out without checking in.")
_isLoading.value = false
postErrorMessage("Error fetching ID }")
}
} else {
postErrorMessage("No attendance found for today. Please check in first.")
}.addOnFailureListener {
_isLoading.value = false
postErrorMessage("Error FailureListener}")
}
}.addOnFailureListener { exception ->
_isLoading.value = false
postErrorMessage("Error fetching document: ${exception.message}")
}
}
} else {
}
}
fun logout(userId: String? = qrCodeValue.value) {
if (qrCodeValue.value != "" && userId != null) {
viewModelScope.launch {
_errorMessage.emit(null)
firebaseFirestore.collection("employees").whereEqualTo("Id", userId).get()
.addOnSuccessListener {
if (!it.isEmpty) {
for (doc in it) {
if (true == doc.getBoolean("EmployeeStatus")) {
viewModelScope.launch {
_userName.value =doc.getString("Name")
putQRvalueEmpty()
putCheckOutAttendance(userId)
}
} else {
_isLoading.value = false
postErrorMessage("ID has been expired }")
}
}
} else {
_isLoading.value = false
postErrorMessage("Error fetching ID }")
}
}.addOnFailureListener {
_isLoading.value = false
postErrorMessage("Error FailureListener}")
}
}
} else {
}
}
private fun putQRvalueEmpty() {
viewModelScope.launch {
_qrCodeValue.value = ""
}
}

View File

@@ -1,54 +0,0 @@
package `in`.sminnovations.attendanceapp.screens.login.data
// File: LoginDataStore.kt
import android.content.Context
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.preferencesDataStore
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
private const val DATASTORE_NAME = "user_prefs"
private val Context.dataStore by preferencesDataStore(name = DATASTORE_NAME)
@Singleton
class LoginDataStore @Inject constructor(@ApplicationContext context: Context) {
private val dataStore = context.dataStore
private val LOGIN_ID_KEY = stringPreferencesKey("login_id")
private val PASSWORD_KEY = stringPreferencesKey("password")
private val IS_LOGGED_IN_KEY = booleanPreferencesKey("is_logged_in")
val loginId: Flow<String> = dataStore.data.map { preferences ->
preferences[LOGIN_ID_KEY] ?: ""
}
val password: Flow<String> = dataStore.data.map { preferences ->
preferences[PASSWORD_KEY] ?: ""
}
val isLoggedIn: Flow<Boolean> = dataStore.data.map { preferences ->
preferences[IS_LOGGED_IN_KEY] ?: false
}
suspend fun saveLoginData(id: String, password: String) {
dataStore.edit { preferences ->
preferences[LOGIN_ID_KEY] = id
preferences[PASSWORD_KEY] = password
preferences[IS_LOGGED_IN_KEY] = true
}
}
suspend fun clearLoginData() {
dataStore.edit { preferences ->
preferences[LOGIN_ID_KEY] = ""
preferences[PASSWORD_KEY] = ""
preferences[IS_LOGGED_IN_KEY] = false
}
}
}

View File

@@ -1,6 +0,0 @@
package `in`.sminnovations.attendanceapp.screens.login.data
data class LoginData(
val id : String ="",
val password: String = ""
)

View File

@@ -1,55 +0,0 @@
package `in`.sminnovations.attendanceapp.screens.login.ui.componets
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
fun OutlinedTextFieldWithError(
value: String,
onValueChange: (String) -> Unit,
label: String,
isError: Boolean,
errorMessage: String,
modifier: Modifier = Modifier,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
visualTransformation: VisualTransformation = VisualTransformation.None
) {
Column(modifier = modifier) {
OutlinedTextField(
value = value,
onValueChange = onValueChange,
label = { Text(label) },
isError = isError,
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
visualTransformation = visualTransformation,
modifier = Modifier.fillMaxWidth(),
colors = OutlinedTextFieldDefaults.colors(
focusedBorderColor = if (isError) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.primary,
unfocusedBorderColor = if (isError) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f),
focusedLabelColor = if (isError) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.primary,
unfocusedLabelColor = if (isError) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.onSurfaceVariant
)
)
if (isError) {
Text(
text = errorMessage,
color = MaterialTheme.colorScheme.error,
style = TextStyle(fontSize = 12.sp),
modifier = Modifier.padding(start = 16.dp, top = 4.dp)
)
}
}
}

View File

@@ -1,155 +0,0 @@
package `in`.sminnovations.attendanceapp.screens.login.ui
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxHeight
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.rememberScrollState
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Lock
import androidx.compose.material.icons.filled.Person
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import `in`.sminnovations.attendanceapp.R
import `in`.sminnovations.attendanceapp.screens.login.ui.componets.OutlinedTextFieldWithError
import `in`.sminnovations.attendanceapp.screens.login.viewModel.LoginViewModel
import kotlinx.coroutines.launch
@Composable
fun LoginScreen(
loginViewModel: LoginViewModel = hiltViewModel(),
onLoginSuccess: () -> Unit
) {
val coroutineScope = rememberCoroutineScope()
val isPasswordError by loginViewModel.isPasswordError.collectAsState()
val isUserIdError by loginViewModel.isIdError.collectAsState()
val isLoggedIn by loginViewModel.isLoggedIn.collectAsState()
var userId by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
var passwordVisible by remember { mutableStateOf(false) }
LaunchedEffect(isLoggedIn) {
if (isLoggedIn) onLoginSuccess()
}
Column(
modifier = Modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(horizontal = 16.dp, vertical = 24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Attendance App", style = MaterialTheme.typography.headlineLarge)
Spacer(modifier = Modifier.height(40.dp))
Image(
painter = painterResource(id = R.drawable.smi_logo),
contentDescription = "App Logo",
modifier = Modifier
.fillMaxWidth(0.5f)
.aspectRatio(1f)
.padding(8.dp)
)
Spacer(modifier = Modifier.height(40.dp))
Text(text = "Credentials", style = MaterialTheme.typography.headlineMedium)
Spacer(modifier = Modifier.weight(1f))
OutlinedTextFieldWithError(
value = userId,
onValueChange = { userId = it },
label = "User ID",
isError = isUserIdError,
errorMessage = "Please enter a valid User ID",
modifier = Modifier.fillMaxWidth(),
leadingIcon = {
Icon(
imageVector = Icons.Default.Person,
contentDescription = "User Icon"
)
}
)
Spacer(modifier = Modifier.height(16.dp))
OutlinedTextFieldWithError(
value = password,
onValueChange = { password = it },
label = "Password",
isError = isPasswordError,
errorMessage = "Please enter a valid password",
modifier = Modifier.fillMaxWidth(),
leadingIcon = {
Icon(
imageVector = Icons.Default.Lock,
contentDescription = "Password Icon"
)
},
trailingIcon = {
IconButton(onClick = { passwordVisible = !passwordVisible }) {
Icon(
painter = painterResource(
id = if (passwordVisible) R.drawable.baseline_visibility_24 else R.drawable.baseline_visibility_off_24
),
contentDescription = if (passwordVisible) "Hide Password" else "Show Password"
)
}
},
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation()
)
Spacer(modifier = Modifier.height(24.dp))
Button(
onClick = {
coroutineScope.launch {
loginViewModel.login(userId, password, onLoginSuccess)
}
},
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
) {
Text(
text = "Login",
fontSize = 20.sp
)
}
Spacer(modifier = Modifier.weight(1f))
}
}

View File

@@ -1,126 +0,0 @@
package `in`.sminnovations.attendanceapp.screens.login.viewModel
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.firebase.firestore.DocumentSnapshot
import com.google.firebase.firestore.FirebaseFirestore
import dagger.hilt.android.lifecycle.HiltViewModel
import `in`.sminnovations.attendanceapp.data.dataStore.Employee
import `in`.sminnovations.attendanceapp.data.dataStore.EmployeeRepository
import `in`.sminnovations.attendanceapp.screens.login.data.LoginData
import `in`.sminnovations.attendanceapp.screens.login.data.LoginDataStore
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import javax.inject.Inject
@HiltViewModel
class LoginViewModel @Inject constructor(
private val loginDataStore: LoginDataStore,
private val firebaseFirestore: FirebaseFirestore,
private val employeeRepository: EmployeeRepository
) : ViewModel() {
private val _isPasswordError = MutableStateFlow(false)
val isPasswordError = _isPasswordError.asStateFlow()
private val _isIDError = MutableStateFlow(false)
val isIdError = _isIDError.asStateFlow()
private val _isLoggedIn = MutableStateFlow(false)
val isLoggedIn = _isLoggedIn.asStateFlow()
private val _loginData = MutableStateFlow(LoginData("", ""))
val loginData = _loginData.asStateFlow()
init {
viewModelScope.launch {
collectLoginData()
}
}
fun collectLoginData(){
viewModelScope.launch {
loginDataStore.isLoggedIn.collect { loggedIn ->
_isLoggedIn.value = loggedIn
if (loggedIn) {
loginDataStore.loginId.collect { id ->
loginDataStore.password.collect { password ->
_loginData.value = LoginData(id, password)
}
}
}
}
}
}
fun login(userId: String, password: String, onLoginSuccess: () -> Unit) {
viewModelScope.launch {
firebaseFirestore.collection("employees").whereEqualTo("Id", userId).get()
.addOnSuccessListener {
if (!it.isEmpty) {
_isIDError.value = false
for (doc in it) {
if (password == doc.getString("Password")) {
if (true == doc.getBoolean("EmployeeStatus")) {
viewModelScope.launch {
loginDataStore.saveLoginData(userId, password)
_isLoggedIn.value = true
}
viewModelScope.launch {
fetchEmployeeData(userId)
onLoginSuccess()
}
}else{
_isIDError.value = true
}
} else {
_isPasswordError.value = true
}
}
} else {
_isIDError.value = true
}
}.addOnFailureListener {
_isIDError.value = true
}
}
}
private fun DocumentSnapshot.toEmployee(): Employee {
return Employee(
androidID = getString("AndroidID") ?: "",
dateOfJoining = getString("DateOfJoining") ?: "",
dateOfLeaving = getString("DateOfLeaving") ?: "",
designation = getString("Designation") ?: "",
employeeStatus = getBoolean("EmployeeStatus") ?: true,
id = getString("Id") ?: "",
name = getString("Name") ?: "",
password = getString("Password") ?: "",
photo = getString("Photo") ?: "",
dateOfBirth = getString("dateOfBirth") ?: ""
)
}
private suspend fun fetchEmployeeData(employeeId: String) {
val db = firebaseFirestore
val document = db.collection("employees").document(employeeId).get().await()
if (document.exists()) {
val savedata = document.toEmployee()
Log.d("FetchSuccess", "Fetched Employee Data: $savedata")
employeeRepository.saveEmployeeData(savedata)
} else {
Log.d("FetchError", "Document does not exist for employee ID: $employeeId")
}
}
}

View File

@@ -1,2 +0,0 @@
package `in`.sminnovations.attendanceapp.screens.qrcode.ui

View File

@@ -1,7 +0,0 @@
package `in`.sminnovations.attendanceapp.screens.settings.data
class EmployeeDataSettings (
val name : String = "",
val id : String = "",
val designation : String = ""
)

View File

@@ -1,33 +0,0 @@
package `in`.sminnovations.attendanceapp.screens.settings.viewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
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 `in`.sminnovations.attendanceapp.screens.settings.data.EmployeeDataSettings
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class SettingsViewModel @Inject constructor(
private val loginDataStore: LoginDataStore,
private val employeeRepository: EmployeeRepository,
private val checkInCheckOutDataStore: CheckInCheckOutDataStore,
) : ViewModel() {
val employeeDataSettings : Flow<EmployeeDataSettings> = employeeRepository.getEmployeeDataSettings()
fun logout() {
viewModelScope.launch {
loginDataStore.clearLoginData()
checkInCheckOutDataStore.clearLoginData()
}
}
}