diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/viewModel/HomeViewModel.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/viewModel/HomeViewModel.kt index 0478579..a821f33 100644 --- a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/viewModel/HomeViewModel.kt +++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/viewModel/HomeViewModel.kt @@ -8,15 +8,19 @@ import android.graphics.Paint import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.google.firebase.firestore.FieldValue import com.google.firebase.firestore.FirebaseFirestore import com.google.zxing.BarcodeFormat import com.journeyapps.barcodescanner.BarcodeEncoder import dagger.hilt.android.lifecycle.HiltViewModel import `in`.sminnovations.smi_attendance_admin.screens.home.data.QRCodeDataStore import `in`.sminnovations.smi_attendance_admin.screens.login.data.LoginDataStore +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import java.text.SimpleDateFormat import java.util.Date @@ -25,13 +29,15 @@ import javax.inject.Inject @HiltViewModel class HomeViewModel @Inject constructor( - private val qrCodeDataStore: QRCodeDataStore, private val firebaseFirestore: FirebaseFirestore + private val qrCodeDataStore: QRCodeDataStore,private val loginDataStore: LoginDataStore,private val firebaseFirestore: FirebaseFirestore ) : ViewModel() { + private val _qrCodeBitmap = MutableStateFlow(null) val qrCodeBitmap: StateFlow = _qrCodeBitmap var isLoading = MutableStateFlow(false) fun checkAndGenerateQRCode() { + val today = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(Date()) val documentRef = firebaseFirestore.collection("qr_key").document(today) @@ -53,32 +59,44 @@ class HomeViewModel @Inject constructor( // Show a toast from your Composable // Example: Toast.makeText(context, "Document already present: $existingKey", Toast.LENGTH_SHORT).show() } else { - // If the document doesn't exist, create it - val randomNumber = (1000..9999).random() // Generate a random 4-digit number - val newKey = "SMI$randomNumber${SimpleDateFormat("MM", Locale.getDefault()).format(Date())}${SimpleDateFormat("dd", Locale.getDefault()).format(Date())}" + viewModelScope.launch { - val newDocument = hashMapOf( - "id" to today, - "key" to newKey // Add your key here - ) + val loginId = loginDataStore.getLoginId() + // If the document doesn't exist, create it + val randomNumber = (1000..9999).random() // Generate a random 4-digit number + val newKey = "SMI$randomNumber${ + SimpleDateFormat( + "MM", + Locale.getDefault() + ).format(Date()) + }${SimpleDateFormat("dd", Locale.getDefault()).format(Date())}" - // Create the document - documentRef.set(newDocument).addOnSuccessListener { - // Set the QR code bitmap - viewModelScope.launch { + val newDocument = hashMapOf( + "id" to today, + "employeeId" to loginId, + "key" to newKey, // Add your key here + "createdAt" to FieldValue.serverTimestamp() - qrCodeDataStore.saveQRData(id = today, key = newKey) + ) - _qrCodeBitmap.value = generateQRCode(newKey) + // Create the document + documentRef.set(newDocument).addOnSuccessListener { + // Set the QR code bitmap + viewModelScope.launch { + qrCodeDataStore.saveQRData(id = today, key = newKey) + + _qrCodeBitmap.value = generateQRCode(newKey) + + isLoading.value = false // Stop loading + } + + }.addOnFailureListener { e -> + // Handle failure isLoading.value = false // Stop loading + // Show a toast from your Composable + // Example: Toast.makeText(context, "Error creating document: ${e.message}", Toast.LENGTH_SHORT).show() } - - }.addOnFailureListener { e -> - // Handle failure - isLoading.value = false // Stop loading - // Show a toast from your Composable - // Example: Toast.makeText(context, "Error creating document: ${e.message}", Toast.LENGTH_SHORT).show() } } }.addOnFailureListener { e -> diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/data/LoginDataStore.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/data/LoginDataStore.kt index 29ba605..ed68bb2 100644 --- a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/data/LoginDataStore.kt +++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/data/LoginDataStore.kt @@ -10,6 +10,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject import javax.inject.Singleton import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map private const val DATASTORE_NAME = "user_prefs" @@ -21,12 +22,16 @@ class LoginDataStore @Inject constructor(@ApplicationContext context: Context) { private val dataStore = context.dataStore private val LOGIN_ID_KEY = stringPreferencesKey("login_id") + private val USER_NAME = stringPreferencesKey("user_name") private val PASSWORD_KEY = stringPreferencesKey("password") private val IS_LOGGED_IN_KEY = booleanPreferencesKey("is_logged_in") val loginId: Flow = dataStore.data.map { preferences -> preferences[LOGIN_ID_KEY] ?: "" } + val userName: Flow = dataStore.data.map { preferences -> + preferences[USER_NAME] ?: "" + } val password: Flow = dataStore.data.map { preferences -> preferences[PASSWORD_KEY] ?: "" @@ -36,9 +41,10 @@ class LoginDataStore @Inject constructor(@ApplicationContext context: Context) { preferences[IS_LOGGED_IN_KEY] ?: false } - suspend fun saveLoginData(id: String, password: String) { + suspend fun saveLoginData(id: String,name: String, password: String) { dataStore.edit { preferences -> preferences[LOGIN_ID_KEY] = id + preferences[USER_NAME] = name preferences[PASSWORD_KEY] = password preferences[IS_LOGGED_IN_KEY] = true } @@ -47,8 +53,13 @@ class LoginDataStore @Inject constructor(@ApplicationContext context: Context) { suspend fun clearLoginData() { dataStore.edit { preferences -> preferences.remove(LOGIN_ID_KEY) + preferences.remove(USER_NAME) preferences.remove(PASSWORD_KEY) preferences[IS_LOGGED_IN_KEY] = false } } + + suspend fun getLoginId(): String { + return dataStore.data.first()[LOGIN_ID_KEY] ?: "" + } } diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/ui/LoginScreen.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/ui/LoginScreen.kt index 998c1e2..19f0e7c 100644 --- a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/ui/LoginScreen.kt +++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/ui/LoginScreen.kt @@ -90,6 +90,7 @@ fun LoginScreen( value = userId, onValueChange = { userId = it }, label = "User ID", + enabled = !loading, isError = isUserIdError, errorMessage = "Please enter a valid User ID", modifier = Modifier.fillMaxWidth(), @@ -107,6 +108,7 @@ fun LoginScreen( value = password, onValueChange = { password = it }, label = "Password", + enabled = !loading, isError = isPasswordError, errorMessage = "Please enter a valid password", modifier = Modifier.fillMaxWidth(), @@ -130,6 +132,11 @@ fun LoginScreen( ) Spacer(modifier = Modifier.height(24.dp)) + LaunchedEffect(isUserIdError, isPasswordError) { + if (isUserIdError || isPasswordError) { + loading = false // Hide the progress bar if there's an error + } + } if (loading) { CircularProgressIndicator( diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/ui/components/OutlinedTextFiledWithErrors.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/ui/components/OutlinedTextFiledWithErrors.kt index 9f30d52..373f857 100644 --- a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/ui/components/OutlinedTextFiledWithErrors.kt +++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/ui/components/OutlinedTextFiledWithErrors.kt @@ -20,6 +20,7 @@ fun OutlinedTextFieldWithError( onValueChange: (String) -> Unit, label: String, isError: Boolean, + enabled: Boolean, errorMessage: String, modifier: Modifier = Modifier, leadingIcon: @Composable (() -> Unit)? = null, @@ -32,6 +33,7 @@ fun OutlinedTextFieldWithError( onValueChange = onValueChange, label = { Text(label) }, isError = isError, + enabled = enabled, leadingIcon = leadingIcon, trailingIcon = trailingIcon, visualTransformation = visualTransformation, diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/viewModel/LoginViewModel.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/viewModel/LoginViewModel.kt index c55ce0b..5bec386 100644 --- a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/viewModel/LoginViewModel.kt +++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/viewModel/LoginViewModel.kt @@ -57,8 +57,9 @@ class LoginViewModel @Inject constructor( _isIDError.value = false for (doc in it) { if (password == doc.getString("Password")) { + val name = doc.getString("Name")!! viewModelScope.launch { - loginDataStore.saveLoginData(userId, password) + loginDataStore.saveLoginData(userId,name, password) _isLoggedIn.value = true onLoginSuccess() diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/components/TopComponents.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/components/TopComponents.kt index b4a51ba..4867e5e 100644 --- a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/components/TopComponents.kt +++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/components/TopComponents.kt @@ -16,6 +16,8 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -34,6 +36,8 @@ fun TopComponents( mainNavHostController : NavHostController, settingsViewModel : SettingsViewModel ) { + val loginId by settingsViewModel.loginId.collectAsState() + val userName by settingsViewModel.userName.collectAsState() Column( modifier = Modifier .fillMaxWidth(), @@ -51,7 +55,7 @@ fun TopComponents( Spacer(modifier = Modifier.height(16.dp)) Text( - text = "Account Name", + text = userName, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold, fontSize = 20.sp, @@ -61,20 +65,20 @@ fun TopComponents( Spacer(modifier = Modifier.height(8.dp)) Text( - text = "ID: 69420", + text = loginId, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 16.sp ) - Spacer(modifier = Modifier.height(4.dp)) - - Text( - text = "Designation", - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.primary, - fontSize = 16.sp - ) +// Spacer(modifier = Modifier.height(4.dp)) +// +// Text( +// text = "Designation", +// style = MaterialTheme.typography.bodyMedium, +// color = MaterialTheme.colorScheme.primary, +// fontSize = 16.sp +// ) Spacer(modifier = Modifier.height(8.dp)) Button( onClick = { diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/viewModel/SettingsViewModel.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/viewModel/SettingsViewModel.kt index 0e0b466..7be2f15 100644 --- a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/viewModel/SettingsViewModel.kt +++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/viewModel/SettingsViewModel.kt @@ -4,9 +4,13 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.google.firebase.firestore.FirebaseFirestore import dagger.hilt.android.lifecycle.HiltViewModel +import `in`.sminnovations.smi_attendance_admin.screens.home.data.QRCodeDataStore import `in`.sminnovations.smi_attendance_admin.screens.login.data.LoginDataStore import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import javax.inject.Inject @@ -15,11 +19,19 @@ class SettingsViewModel @Inject constructor( private val loginDataStore: LoginDataStore, private val firebaseFirestore: FirebaseFirestore ) : ViewModel() { - + val loginId: StateFlow = loginDataStore.loginId.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5000), + initialValue = "" + ) + val userName: StateFlow = loginDataStore.userName.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5000), + initialValue = "" + ) fun logout() { viewModelScope.launch { loginDataStore.clearLoginData() } } - } \ No newline at end of file