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.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<Bitmap?>(null)
val qrCodeBitmap: StateFlow<Bitmap?> = _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 ->

View File

@@ -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<String> = dataStore.data.map { preferences ->
preferences[LOGIN_ID_KEY] ?: ""
}
val userName: Flow<String> = dataStore.data.map { preferences ->
preferences[USER_NAME] ?: ""
}
val password: Flow<String> = 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] ?: ""
}
}

View File

@@ -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(

View File

@@ -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,

View File

@@ -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()

View File

@@ -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 = {

View File

@@ -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<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() {
viewModelScope.launch {
loginDataStore.clearLoginData()
}
}
}