LoginScreen

This commit is contained in:
sathwikcs
2024-10-16 17:38:20 +05:30
parent 6ccab6e184
commit ed354c7799
2 changed files with 130 additions and 68 deletions

View File

@@ -1,14 +1,22 @@
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
@@ -36,23 +44,23 @@ 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 isLoading by loginViewModel.isLoading.collectAsState()
val isPasswordError by loginViewModel.isPasswordError.collectAsState()
val isUserIdError by loginViewModel.isIdError.collectAsState()
val isLoggedIn by loginViewModel.isLoggedIn.collectAsState()
var userId by remember { mutableStateOf(TextFieldValue("")) }
var password by remember { mutableStateOf(TextFieldValue("")) }
var userId by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
var passwordVisible by remember { mutableStateOf(false) }
// Navigate to the main screen if the user is already logged in
LaunchedEffect(isLoggedIn) {
if (isLoggedIn) onLoginSuccess()
}
@@ -60,81 +68,88 @@ fun LoginScreen(
Column(
modifier = Modifier
.fillMaxSize()
.padding(26.dp),
.verticalScroll(rememberScrollState())
.padding(horizontal = 16.dp, vertical = 24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Attendance App", style = MaterialTheme.typography.headlineLarge)
Spacer(modifier = Modifier.height(50.dp))
Spacer(modifier = Modifier.height(40.dp))
// Logo Image
Image(
painter = painterResource(id = R.drawable.smi_logo),
contentDescription = "App Logo",
alignment = Alignment.TopCenter
modifier = Modifier
.fillMaxWidth(0.5f)
.aspectRatio(1f)
.padding(8.dp)
)
Spacer(modifier = Modifier.height(100.dp))
Spacer(modifier = Modifier.height(40.dp))
Text(text = "Credentials", style = MaterialTheme.typography.headlineMedium)
Spacer(modifier = Modifier.height(20.dp))
Spacer(modifier = Modifier.weight(1f))
// User ID TextField
OutlinedTextField(
OutlinedTextFieldWithError(
value = userId,
onValueChange = { userId = it },
label = { Text("User ID") },
label = "User ID",
isError = isUserIdError,
errorMessage = "Please enter a valid User ID",
modifier = Modifier.fillMaxWidth(),
keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Next)
)
Spacer(modifier = Modifier.height(30.dp))
// Password TextField
OutlinedTextField(
value = password,
onValueChange = { password = it },
label = { Text("Password") },
modifier = Modifier.fillMaxWidth(),
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done),
trailingIcon = {
val icon = if (passwordVisible) {
painterResource(id = R.drawable.baseline_visibility_24)
} else {
painterResource(id = R.drawable.baseline_visibility_off_24)
}
IconButton(onClick = { passwordVisible = !passwordVisible }) {
Icon(painter = icon, contentDescription = "Toggle Password Visibility")
}
leadingIcon = {
Icon(
imageVector = Icons.Default.Person,
contentDescription = "User Icon"
)
}
)
Spacer(modifier = Modifier.height(60.dp))
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))
// Login Button
Button(
onClick = {
coroutineScope.launch {
loginViewModel.login(userId.text, password.text, onLoginSuccess)
loginViewModel.login(userId, password, onLoginSuccess)
}
},
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
enabled = !isLoading
) {
if (isLoading) {
CircularProgressIndicator(
color = Color.White,
modifier = Modifier.size(24.dp),
strokeWidth = 2.dp
)
} else {
Text(
text = "Login",
fontSize = 20.sp
)
}
Text(
text = "Login",
fontSize = 20.sp
)
}
Spacer(modifier = Modifier.weight(1f))
}
}
}

View File

@@ -1,30 +1,35 @@
package `in`.sminnovations.attendanceapp.screens.login.viewModel
// File: LoginViewModel.kt
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.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.delay
import kotlinx.coroutines.tasks.await
import javax.inject.Inject
@HiltViewModel
class LoginViewModel @Inject constructor(
private val loginDataStore: LoginDataStore
private val loginDataStore: LoginDataStore, private val firebaseFirestore: FirebaseFirestore
) : ViewModel() {
private val _isLoading = MutableStateFlow(false)
val isLoading = _isLoading.asStateFlow()
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()
@@ -41,20 +46,35 @@ class LoginViewModel @Inject constructor(
}
}
}
}
fun login(userId: String, password: String, onLoginSuccess: () -> Unit) {
viewModelScope.launch {
_isLoading.value = true
delay(1000) // Simulate network call
firebaseFirestore.collection("employees").whereEqualTo("Id", userId).get()
.addOnSuccessListener {
if (!it.isEmpty) {
_isIDError.value = false
for (doc in it) {
if (password == doc.getString("Password")) {
viewModelScope.launch {
loginDataStore.saveLoginData(userId, password)
_isLoggedIn.value = true
onLoginSuccess()
if (userId == "1" && password == "2") {
loginDataStore.saveLoginData(userId, password)
_isLoggedIn.value = true
onLoginSuccess()
}
_isLoading.value = false
}
} else {
_isPasswordError.value = true
}
}
} else {
_isIDError.value = true
}
}.addOnFailureListener {
_isIDError.value = true
}
}
}
fun logout() {
@@ -63,4 +83,31 @@ class LoginViewModel @Inject constructor(
_isLoggedIn.value = false
}
}
private fun DocumentSnapshot.toEmployee(): Employee {
return Employee(
androidID = getString("AndroidID") ?: "",
dateOfJoining = getString("DateOfJoining") ?: "",
dateOfLeaving = getString("DateOfLeaving") ?: "",
designation = getString("Designation") ?: "Android Developer",
employeeStatus = getBoolean("EmployeeStatus") ?: true,
id = getString("Id") ?: "",
name = getString("Name") ?: "",
password = getString("Password") ?: "",
photo = getString("Photo") ?: "",
dateOfBirth = getString("dateOfBirth") ?: ""
)
}
suspend fun fetchEmployeeData(employeeId: String): Employee? {
val db = FirebaseFirestore.getInstance()
return try {
val document = db.collection("employees").document(employeeId).get().await()
document.toEmployee()
} catch (e: Exception) {
e.printStackTrace()
null
}
}
}