Changes in logic and backend

This commit is contained in:
chandrashekhar reddy
2024-10-18 18:15:43 +05:30
parent 327782ca4a
commit f808b4db74
7 changed files with 89 additions and 34 deletions

View File

@@ -8,15 +8,19 @@ import android.graphics.Paint
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.google.firebase.firestore.FieldValue
import com.google.firebase.firestore.FirebaseFirestore import com.google.firebase.firestore.FirebaseFirestore
import com.google.zxing.BarcodeFormat import com.google.zxing.BarcodeFormat
import com.journeyapps.barcodescanner.BarcodeEncoder import com.journeyapps.barcodescanner.BarcodeEncoder
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import `in`.sminnovations.smi_attendance_admin.screens.home.data.QRCodeDataStore import `in`.sminnovations.smi_attendance_admin.screens.home.data.QRCodeDataStore
import `in`.sminnovations.smi_attendance_admin.screens.login.data.LoginDataStore import `in`.sminnovations.smi_attendance_admin.screens.login.data.LoginDataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
@@ -25,13 +29,15 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class HomeViewModel @Inject constructor( 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() { ) : ViewModel() {
private val _qrCodeBitmap = MutableStateFlow<Bitmap?>(null) private val _qrCodeBitmap = MutableStateFlow<Bitmap?>(null)
val qrCodeBitmap: StateFlow<Bitmap?> = _qrCodeBitmap val qrCodeBitmap: StateFlow<Bitmap?> = _qrCodeBitmap
var isLoading = MutableStateFlow(false) var isLoading = MutableStateFlow(false)
fun checkAndGenerateQRCode() { fun checkAndGenerateQRCode() {
val today = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(Date()) val today = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(Date())
val documentRef = firebaseFirestore.collection("qr_key").document(today) val documentRef = firebaseFirestore.collection("qr_key").document(today)
@@ -53,32 +59,44 @@ class HomeViewModel @Inject constructor(
// Show a toast from your Composable // Show a toast from your Composable
// Example: Toast.makeText(context, "Document already present: $existingKey", Toast.LENGTH_SHORT).show() // Example: Toast.makeText(context, "Document already present: $existingKey", Toast.LENGTH_SHORT).show()
} else { } else {
// If the document doesn't exist, create it viewModelScope.launch {
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())}"
val newDocument = hashMapOf( val loginId = loginDataStore.getLoginId()
"id" to today, // If the document doesn't exist, create it
"key" to newKey // Add your key here 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 val newDocument = hashMapOf(
documentRef.set(newDocument).addOnSuccessListener { "id" to today,
// Set the QR code bitmap "employeeId" to loginId,
viewModelScope.launch { "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 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 -> }.addOnFailureListener { e ->

View File

@@ -10,6 +10,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
private const val DATASTORE_NAME = "user_prefs" 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 dataStore = context.dataStore
private val LOGIN_ID_KEY = stringPreferencesKey("login_id") private val LOGIN_ID_KEY = stringPreferencesKey("login_id")
private val USER_NAME = stringPreferencesKey("user_name")
private val PASSWORD_KEY = stringPreferencesKey("password") private val PASSWORD_KEY = stringPreferencesKey("password")
private val IS_LOGGED_IN_KEY = booleanPreferencesKey("is_logged_in") private val IS_LOGGED_IN_KEY = booleanPreferencesKey("is_logged_in")
val loginId: Flow<String> = dataStore.data.map { preferences -> val loginId: Flow<String> = dataStore.data.map { preferences ->
preferences[LOGIN_ID_KEY] ?: "" preferences[LOGIN_ID_KEY] ?: ""
} }
val userName: Flow<String> = dataStore.data.map { preferences ->
preferences[USER_NAME] ?: ""
}
val password: Flow<String> = dataStore.data.map { preferences -> val password: Flow<String> = dataStore.data.map { preferences ->
preferences[PASSWORD_KEY] ?: "" preferences[PASSWORD_KEY] ?: ""
@@ -36,9 +41,10 @@ class LoginDataStore @Inject constructor(@ApplicationContext context: Context) {
preferences[IS_LOGGED_IN_KEY] ?: false 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 -> dataStore.edit { preferences ->
preferences[LOGIN_ID_KEY] = id preferences[LOGIN_ID_KEY] = id
preferences[USER_NAME] = name
preferences[PASSWORD_KEY] = password preferences[PASSWORD_KEY] = password
preferences[IS_LOGGED_IN_KEY] = true preferences[IS_LOGGED_IN_KEY] = true
} }
@@ -47,8 +53,13 @@ class LoginDataStore @Inject constructor(@ApplicationContext context: Context) {
suspend fun clearLoginData() { suspend fun clearLoginData() {
dataStore.edit { preferences -> dataStore.edit { preferences ->
preferences.remove(LOGIN_ID_KEY) preferences.remove(LOGIN_ID_KEY)
preferences.remove(USER_NAME)
preferences.remove(PASSWORD_KEY) preferences.remove(PASSWORD_KEY)
preferences[IS_LOGGED_IN_KEY] = false preferences[IS_LOGGED_IN_KEY] = false
} }
} }
suspend fun getLoginId(): String {
return dataStore.data.first()[LOGIN_ID_KEY] ?: ""
}
} }

View File

@@ -90,6 +90,7 @@ fun LoginScreen(
value = userId, value = userId,
onValueChange = { userId = it }, onValueChange = { userId = it },
label = "User ID", label = "User ID",
enabled = !loading,
isError = isUserIdError, isError = isUserIdError,
errorMessage = "Please enter a valid User ID", errorMessage = "Please enter a valid User ID",
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
@@ -107,6 +108,7 @@ fun LoginScreen(
value = password, value = password,
onValueChange = { password = it }, onValueChange = { password = it },
label = "Password", label = "Password",
enabled = !loading,
isError = isPasswordError, isError = isPasswordError,
errorMessage = "Please enter a valid password", errorMessage = "Please enter a valid password",
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
@@ -130,6 +132,11 @@ fun LoginScreen(
) )
Spacer(modifier = Modifier.height(24.dp)) 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) { if (loading) {
CircularProgressIndicator( CircularProgressIndicator(

View File

@@ -20,6 +20,7 @@ fun OutlinedTextFieldWithError(
onValueChange: (String) -> Unit, onValueChange: (String) -> Unit,
label: String, label: String,
isError: Boolean, isError: Boolean,
enabled: Boolean,
errorMessage: String, errorMessage: String,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
leadingIcon: @Composable (() -> Unit)? = null, leadingIcon: @Composable (() -> Unit)? = null,
@@ -32,6 +33,7 @@ fun OutlinedTextFieldWithError(
onValueChange = onValueChange, onValueChange = onValueChange,
label = { Text(label) }, label = { Text(label) },
isError = isError, isError = isError,
enabled = enabled,
leadingIcon = leadingIcon, leadingIcon = leadingIcon,
trailingIcon = trailingIcon, trailingIcon = trailingIcon,
visualTransformation = visualTransformation, visualTransformation = visualTransformation,

View File

@@ -57,8 +57,9 @@ class LoginViewModel @Inject constructor(
_isIDError.value = false _isIDError.value = false
for (doc in it) { for (doc in it) {
if (password == doc.getString("Password")) { if (password == doc.getString("Password")) {
val name = doc.getString("Name")!!
viewModelScope.launch { viewModelScope.launch {
loginDataStore.saveLoginData(userId, password) loginDataStore.saveLoginData(userId,name, password)
_isLoggedIn.value = true _isLoggedIn.value = true
onLoginSuccess() onLoginSuccess()

View File

@@ -16,6 +16,8 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
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.getValue
import androidx.compose.ui.Alignment 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.draw.clip
@@ -34,6 +36,8 @@ fun TopComponents(
mainNavHostController : NavHostController, mainNavHostController : NavHostController,
settingsViewModel : SettingsViewModel settingsViewModel : SettingsViewModel
) { ) {
val loginId by settingsViewModel.loginId.collectAsState()
val userName by settingsViewModel.userName.collectAsState()
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth(), .fillMaxWidth(),
@@ -51,7 +55,7 @@ fun TopComponents(
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
Text( Text(
text = "Account Name", text = userName,
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
fontSize = 20.sp, fontSize = 20.sp,
@@ -61,20 +65,20 @@ fun TopComponents(
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Text( Text(
text = "ID: 69420", text = loginId,
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant, color = MaterialTheme.colorScheme.onSurfaceVariant,
fontSize = 16.sp fontSize = 16.sp
) )
Spacer(modifier = Modifier.height(4.dp)) // Spacer(modifier = Modifier.height(4.dp))
//
Text( // Text(
text = "Designation", // text = "Designation",
style = MaterialTheme.typography.bodyMedium, // style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.primary, // color = MaterialTheme.colorScheme.primary,
fontSize = 16.sp // fontSize = 16.sp
) // )
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Button( Button(
onClick = { onClick = {

View File

@@ -4,9 +4,13 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.google.firebase.firestore.FirebaseFirestore import com.google.firebase.firestore.FirebaseFirestore
import dagger.hilt.android.lifecycle.HiltViewModel 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 `in`.sminnovations.smi_attendance_admin.screens.login.data.LoginDataStore
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@@ -15,11 +19,19 @@ class SettingsViewModel @Inject constructor(
private val loginDataStore: LoginDataStore, private val loginDataStore: LoginDataStore,
private val firebaseFirestore: FirebaseFirestore private val firebaseFirestore: FirebaseFirestore
) : ViewModel() { ) : ViewModel() {
val loginId: StateFlow<String> = loginDataStore.loginId.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = ""
)
val userName: StateFlow<String> = loginDataStore.userName.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = ""
)
fun logout() { fun logout() {
viewModelScope.launch { viewModelScope.launch {
loginDataStore.clearLoginData() loginDataStore.clearLoginData()
} }
} }
} }