diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..44ca2d9
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 33e1094..d653f13 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,6 +1,10 @@
plugins {
+ kotlin("kapt")
+ id("com.google.dagger.hilt.android")
+ id("com.google.gms.google-services")
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
+
}
android {
@@ -8,7 +12,7 @@ android {
compileSdk = 34
defaultConfig {
- applicationId = "in.sminnovations.smi_attendance_admin"
+ applicationId = "in.sminnovations.attendanceapp.admin"
minSdk = 26
targetSdk = 34
versionCode = 1
@@ -47,6 +51,10 @@ android {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
+ // Allow references to generated code
+ kapt {
+ correctErrorTypes = true
+ }
}
dependencies {
@@ -59,6 +67,8 @@ dependencies {
implementation(libs.androidx.ui.graphics)
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
+ implementation(libs.androidx.datastore.core.android)
+ implementation(libs.androidx.datastore.preferences.core.jvm)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
@@ -66,4 +76,32 @@ dependencies {
androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)
+
+ implementation ("androidx.camera:camera-camera2:1.3.4")
+ implementation ( "androidx.camera:camera-lifecycle:1.3.4")
+ implementation ("androidx.camera:camera-view:1.3.4")
+ implementation ("com.google.mlkit:barcode-scanning:17.3.0")
+ implementation ("com.google.accompanist:accompanist-permissions:0.31.2-alpha")
+
+ implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6")
+
+ implementation ("androidx.navigation:navigation-compose:2.7.2")
+
+ implementation("androidx.datastore:datastore-preferences:1.1.1")
+
+ implementation("com.google.dagger:hilt-android:2.51.1")
+ kapt("com.google.dagger:hilt-android-compiler:2.51.1")
+ implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
+
+ val nav_version = "2.8.2"
+ implementation("androidx.navigation:navigation-compose:$nav_version")
+
+ // Import the Firebase BoM
+ implementation(platform("com.google.firebase:firebase-bom:33.4.0"))
+ // When using the BoM, you don't specify versions in Firebase library dependencies
+ // Add the dependency for the Firebase SDK for Google Analytics
+ implementation("com.google.firebase:firebase-analytics")
+ implementation("com.google.firebase:firebase-firestore")
+ //Qr code generator
+ implementation("com.journeyapps:zxing-android-embedded:4.3.0")
}
\ No newline at end of file
diff --git a/app/google-services.json b/app/google-services.json
new file mode 100644
index 0000000..7b39403
--- /dev/null
+++ b/app/google-services.json
@@ -0,0 +1,48 @@
+{
+ "project_info": {
+ "project_number": "482294935697",
+ "project_id": "attendenceapp-57022",
+ "storage_bucket": "attendenceapp-57022.appspot.com"
+ },
+ "client": [
+ {
+ "client_info": {
+ "mobilesdk_app_id": "1:482294935697:android:07559f83f8f740be6c8f30",
+ "android_client_info": {
+ "package_name": "in.sminnovations.attendanceapp.admin"
+ }
+ },
+ "oauth_client": [],
+ "api_key": [
+ {
+ "current_key": "AIzaSyA0H9rJ8rML0JeBvN8rx0V2ijSA0GEfKFo"
+ }
+ ],
+ "services": {
+ "appinvite_service": {
+ "other_platform_oauth_client": []
+ }
+ }
+ },
+ {
+ "client_info": {
+ "mobilesdk_app_id": "1:482294935697:android:89783c6f1e52abd76c8f30",
+ "android_client_info": {
+ "package_name": "in.sminnovations.attendanceapp.user"
+ }
+ },
+ "oauth_client": [],
+ "api_key": [
+ {
+ "current_key": "AIzaSyA0H9rJ8rML0JeBvN8rx0V2ijSA0GEfKFo"
+ }
+ ],
+ "services": {
+ "appinvite_service": {
+ "other_platform_oauth_client": []
+ }
+ }
+ }
+ ],
+ "configuration_version": "1"
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1002775..b0d955e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools">
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/AppClass.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/AppClass.kt
new file mode 100644
index 0000000..856a55c
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/AppClass.kt
@@ -0,0 +1,12 @@
+package `in`.sminnovations.smi_attendance_admin
+// File: MyApp.kt
+
+import android.app.Application
+import dagger.hilt.android.HiltAndroidApp
+
+@HiltAndroidApp
+class MyApp : Application(){
+
+}
+
+
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/AppNavigation.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/AppNavigation.kt
new file mode 100644
index 0000000..99fe862
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/AppNavigation.kt
@@ -0,0 +1,44 @@
+package `in`.sminnovations.smi_attendance_admin
+
+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.smi_attendance_admin.screens.login.ui.LoginScreen
+
+@Composable
+fun AppNavigation() {
+ val navController = rememberNavController()
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
+ NavigationHost(navController = navController)
+ }
+}
+
+annotation class Composable
+
+@RequiresApi(Build.VERSION_CODES.O_MR1)
+@Composable
+fun NavigationHost(navController: NavHostController) {
+ NavHost(navController = navController, startDestination = "login") {
+ composable("login") {
+ LoginScreen(
+ navController,
+ loginViewModel = hiltViewModel(),
+ onLoginSuccess = {
+ navController.navigate("main") {
+ popUpTo("login") { inclusive = true }
+ }
+ }
+ )
+ }
+
+ composable("main") {
+ MainScreen()
+ }
+ }
+}
+
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/MainActivity.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/MainActivity.kt
index aa2be12..bc6ca27 100644
--- a/app/src/main/java/in/sminnovations/smi_attendance_admin/MainActivity.kt
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/MainActivity.kt
@@ -1,6 +1,7 @@
package `in`.sminnovations.smi_attendance_admin
import android.os.Bundle
+import android.view.WindowManager
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
@@ -11,37 +12,30 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
+import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.smi_attendance_admin.ui.theme.SMIAdminAttendanceTheme
+@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
SMIAdminAttendanceTheme {
- Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
- Greeting(
- name = "Android",
- modifier = Modifier.padding(innerPadding)
- )
- }
+ AppNavigation()
}
}
+
+ }
+ override fun onResume() {
+ super.onResume()
+ // Keep the screen on when the activity is in the foreground
+ window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+ }
+
+ override fun onPause() {
+ super.onPause()
+ // Remove the flag when the activity is not visible
+ window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
-
-@Composable
-fun Greeting(name: String, modifier: Modifier = Modifier) {
- Text(
- text = "Hello $name!",
- modifier = modifier
- )
-}
-
-@Preview(showBackground = true)
-@Composable
-fun GreetingPreview() {
- SMIAdminAttendanceTheme {
- Greeting("Android")
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/MainScreen.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/MainScreen.kt
new file mode 100644
index 0000000..59d6183
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/MainScreen.kt
@@ -0,0 +1,31 @@
+package `in`.sminnovations.smi_attendance_admin
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Scaffold
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.rememberNavController
+import `in`.sminnovations.smi_attendance_admin.navigation.BottomNavigationBar
+import `in`.sminnovations.smi_attendance_admin.navigation.Navigation
+import `in`.sminnovations.smi_attendance_admin.navigation.data.navItems
+
+
+@Composable
+fun MainScreen(
+) {
+ val navController = rememberNavController()
+
+ Scaffold(
+ bottomBar = {
+ BottomNavigationBar(navController, navItems)
+ },
+ content = { padding ->
+ Box(modifier = Modifier.padding(padding)) {
+ Navigation(navController = navController, navItems)
+ }
+ },
+ )
+}
+
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/data/dataStore/Employee.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/data/dataStore/Employee.kt
new file mode 100644
index 0000000..5b7c9fa
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/data/dataStore/Employee.kt
@@ -0,0 +1,14 @@
+package `in`.sminnovations.smi_attendance_admin.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 = ""
+)
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/di/AppModule.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/di/AppModule.kt
new file mode 100644
index 0000000..74dc833
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/di/AppModule.kt
@@ -0,0 +1,32 @@
+package `in`.sminnovations.smi_attendance_admin.di
+
+import android.content.Context
+import com.google.firebase.firestore.FirebaseFirestore
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.components.SingletonComponent
+import `in`.sminnovations.smi_attendance_admin.screens.login.data.LoginDataStore
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+object AppModule {
+ @Provides
+ @Singleton
+ fun provideLoginDataStore(@ApplicationContext context: Context): LoginDataStore {
+ return LoginDataStore(context)
+ }
+ @Provides
+ @Singleton
+ fun provideFirebase(): FirebaseFirestore {
+ return FirebaseFirestore.getInstance()
+ }
+
+// fun provideFirebase(): FirebaseFirestore {
+// return FirebaseFirestore.getInstance()
+// }
+
+
+}
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/navigation/BottomNavBar.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/navigation/BottomNavBar.kt
new file mode 100644
index 0000000..652755a
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/navigation/BottomNavBar.kt
@@ -0,0 +1,48 @@
+package `in`.sminnovations.smi_attendance_admin.navigation
+
+import androidx.compose.material3.NavigationBar
+import androidx.compose.material3.NavigationBarItem
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.navigation.NavController
+import androidx.navigation.compose.currentBackStackEntryAsState
+import `in`.sminnovations.smi_attendance_admin.navigation.data.BottomNavItem
+
+
+@Composable
+fun BottomNavigationBar(
+ navController: NavController,
+ items: List,
+) {
+ NavigationBar {
+ val navBackStackEntry by navController.currentBackStackEntryAsState()
+ val currentRoute = navBackStackEntry?.destination?.route
+ items.forEach { item ->
+ NavigationBarItem(icon = {
+ BottomNavAnimatedIcon(
+ isSelected = currentRoute == item.route,
+ icon = item.icon,
+ selectedIcon = item.selectedIcon,
+ contentDescription = item.label
+ )
+ },
+ label = { Text(text = item.label) },
+ alwaysShowLabel = true,
+ selected = currentRoute == item.route,
+ onClick = {
+ navController.navigate(item.route) {
+ navController.graph.startDestinationRoute?.let { route ->
+ popUpTo(route) {
+ saveState = true
+ }
+ }
+ launchSingleTop = true
+ restoreState = true
+ }
+ })
+ }
+ }
+
+}
+
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/navigation/NavAnimation.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/navigation/NavAnimation.kt
new file mode 100644
index 0000000..b7fcd22
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/navigation/NavAnimation.kt
@@ -0,0 +1,33 @@
+package `in`.sminnovations.smi_attendance_admin.navigation
+
+import androidx.compose.animation.AnimatedContent
+import androidx.compose.animation.core.tween
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.togetherWith
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.graphics.vector.ImageVector
+
+
+@Composable
+fun BottomNavAnimatedIcon(
+ isSelected: Boolean,
+ icon: ImageVector,
+ selectedIcon: ImageVector,
+ contentDescription: String?
+) {
+ AnimatedContent(
+ targetState = isSelected,
+ transitionSpec = {
+ fadeIn(animationSpec = tween(300)) togetherWith fadeOut(animationSpec = tween(300))
+ }, label = "animated icon"
+ ) { targetState ->
+ Icon(
+ imageVector = if (targetState) selectedIcon else icon,
+ contentDescription = contentDescription,
+ tint = if (targetState) MaterialTheme.colorScheme.surface else MaterialTheme.colorScheme.onSurface
+ )
+ }
+}
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/navigation/Navigation.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/navigation/Navigation.kt
new file mode 100644
index 0000000..6c38e2e
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/navigation/Navigation.kt
@@ -0,0 +1,27 @@
+package `in`.sminnovations.smi_attendance_admin.navigation
+
+import androidx.compose.runtime.Composable
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.composable
+import `in`.sminnovations.smi_attendance_admin.screens.home.ui.HomeScreen
+import `in`.sminnovations.smi_attendance_admin.screens.settings.SettingsScreen
+import `in`.sminnovations.smi_attendance_admin.navigation.data.BottomNavItem
+
+
+@Composable
+fun Navigation(
+ navController: NavHostController,
+ items: List,
+) {
+ NavHost(navController, startDestination = items[0].route) {
+ composable(items[0].route) {
+ HomeScreen()
+ }
+ composable(items[1].route) {
+ SettingsScreen()
+ }
+ }
+
+}
+
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/navigation/data/NavigationItem.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/navigation/data/NavigationItem.kt
new file mode 100644
index 0000000..73d1b13
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/navigation/data/NavigationItem.kt
@@ -0,0 +1,23 @@
+package `in`.sminnovations.smi_attendance_admin.navigation.data
+
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.AddCircle
+import androidx.compose.material.icons.filled.Home
+import androidx.compose.material.icons.filled.Search
+import androidx.compose.material.icons.filled.Settings
+import androidx.compose.material.icons.outlined.AddCircle
+import androidx.compose.material.icons.outlined.Home
+import androidx.compose.material.icons.outlined.Search
+import androidx.compose.material.icons.outlined.Settings
+import androidx.compose.ui.graphics.vector.ImageVector
+
+data class BottomNavItem(
+ val icon: ImageVector,
+ val selectedIcon: ImageVector,
+ val label: String,
+ val route: String
+)
+val navItems = listOf(
+ BottomNavItem(Icons.Outlined.Home, Icons.Filled.Home, "Home", "home"),
+ BottomNavItem(Icons.Outlined.Settings, Icons.Filled.Settings, "Settings", "settings")
+)
\ No newline at end of file
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/data/EmployeeData.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/data/EmployeeData.kt
new file mode 100644
index 0000000..b9b391b
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/data/EmployeeData.kt
@@ -0,0 +1,3 @@
+package `in`.sminnovations.smi_attendance_admin.screens.home.data
+
+class EmployeeData
\ No newline at end of file
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/HomeScreen.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/HomeScreen.kt
new file mode 100644
index 0000000..360fa66
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/HomeScreen.kt
@@ -0,0 +1,158 @@
+package `in`.sminnovations.smi_attendance_admin.screens.home.ui
+
+import android.Manifest
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import androidx.activity.compose.BackHandler
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.content.MediaType.Companion.Image
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.RoundedCornerShape
+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.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.RectangleShape
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.Dialog
+import androidx.lifecycle.viewmodel.compose.viewModel
+import com.google.accompanist.permissions.ExperimentalPermissionsApi
+import com.google.accompanist.permissions.isGranted
+import com.google.accompanist.permissions.rememberPermissionState
+import com.google.zxing.BarcodeFormat
+import com.journeyapps.barcodescanner.BarcodeEncoder
+import `in`.sminnovations.smi_attendance_admin.screens.home.ui.componets.LargeButton
+import `in`.sminnovations.smi_attendance_admin.screens.home.viewModel.HomeViewModel
+
+
+@OptIn(ExperimentalPermissionsApi::class)
+@Composable
+fun HomeScreen(viewModel: HomeViewModel = viewModel()) {
+ val isScanning by viewModel.isScanning.collectAsState()
+ val qrCodeValue by viewModel.qrCodeValue.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
+ }
+ }
+
+ Box(modifier = Modifier.fillMaxSize()) {
+
+ QRCodeGeneratorScreen()
+ }
+}
+@Composable
+fun QRCodeGeneratorScreen() {
+ var qrCodeBitmap by remember { mutableStateOf(null) }
+ var isButtonVisible by remember { mutableStateOf(true) }
+ var isFullScreen by remember { mutableStateOf(false) }
+
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(16.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+ // Show the button if it hasn't been clicked yet
+ if (isButtonVisible) {
+ Button(
+ onClick = {
+ val qrData = "Your Data Here" // Replace this with the data you want to encode
+ qrCodeBitmap = generateQRCode(qrData)
+ isButtonVisible = false // Hide the button once QR is generated
+ },
+ modifier = Modifier.padding(bottom = 16.dp)
+ ) {
+ Text(text = "Generate QR Code")
+ }
+ }
+
+ // Display the QR code if it has been generated
+ qrCodeBitmap?.let { bitmap ->
+ Image(
+ bitmap = bitmap.asImageBitmap(),
+ contentDescription = "Generated QR Code",
+ modifier = Modifier
+ .size(250.dp)
+ .padding(16.dp)
+ .clickable {
+ isFullScreen = true // Open full-screen mode on click
+ }
+ )
+ }
+ }
+
+ // Full-Screen Dialog for QR Code
+ if (isFullScreen) {
+ Dialog(onDismissRequest = { isFullScreen = false }) {
+ Box(
+ modifier = Modifier
+ .background(color = MaterialTheme.colorScheme.onBackground, shape = RectangleShape)
+ .fillMaxSize()
+ .clickable { isFullScreen = false } // Close full screen when clicked
+ ) {
+ qrCodeBitmap?.let { bitmap ->
+ Image(
+ bitmap = bitmap.asImageBitmap(),
+ contentDescription = "Full Screen QR Code",
+ modifier = Modifier
+ .fillMaxSize() // Make the image fill the entire screen
+ .clickable {
+ isFullScreen = false // Close full-screen mode on click
+ }
+ )
+ }
+ }
+ }
+ }
+}
+
+// Function to generate QR Code bitmap with black background and white QR code
+fun generateQRCode(data: String): Bitmap? {
+ return try {
+ val barcodeEncoder = BarcodeEncoder()
+ val qrBitmap = barcodeEncoder.encodeBitmap(data, BarcodeFormat.QR_CODE, 1080, 1080)
+
+ // Create a new bitmap with black background
+ val finalBitmap = Bitmap.createBitmap(qrBitmap.width, qrBitmap.height, Bitmap.Config.ARGB_8888)
+ val canvas = Canvas(finalBitmap)
+ val paint = Paint()
+
+ // Set the background to black
+ paint.color = Color.BLACK
+ canvas.drawRect(0f, 0f, qrBitmap.width.toFloat(), qrBitmap.height.toFloat(), paint)
+
+ // Draw the original QR code (white pixels) over the black background
+ canvas.drawBitmap(qrBitmap, 0f, 0f, null)
+
+ finalBitmap
+ } catch (e: Exception) {
+ e.printStackTrace()
+ null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/componets/Card.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/componets/Card.kt
new file mode 100644
index 0000000..6d569db
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/componets/Card.kt
@@ -0,0 +1,2 @@
+package `in`.sminnovations.smi_attendance_admin.screens.home.ui.componets
+
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/componets/LargeButton.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/componets/LargeButton.kt
new file mode 100644
index 0000000..3c5f48b
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/componets/LargeButton.kt
@@ -0,0 +1,40 @@
+package `in`.sminnovations.smi_attendance_admin.screens.home.ui.componets
+
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Button
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+
+@Composable
+fun LargeButton(
+ text: String,
+ onClick: () -> Unit,
+ modifier: Modifier = Modifier
+) {
+ Button(
+ onClick = onClick,
+ modifier = modifier
+ .height(56.dp)
+ .width(200.dp),
+ colors = ButtonDefaults.buttonColors(
+ containerColor = MaterialTheme.colorScheme.primary,
+ contentColor = MaterialTheme.colorScheme.onPrimary
+ ),
+ shape = RoundedCornerShape(28.dp)
+ ) {
+ Text(
+ text = text,
+ fontSize = 18.sp,
+ fontWeight = FontWeight.Bold
+ )
+ }
+}
+
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/componets/QRscreen.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/componets/QRscreen.kt
new file mode 100644
index 0000000..0526477
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/componets/QRscreen.kt
@@ -0,0 +1,29 @@
+package `in`.sminnovations.smi_attendance_admin.screens.home.ui.componets
+
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.Text
+import androidx.compose.runtime.*
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+
+
+@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))
+ }
+ }
+}
+
+
+
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/componets/Qrscanner.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/componets/Qrscanner.kt
new file mode 100644
index 0000000..de73a5c
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/componets/Qrscanner.kt
@@ -0,0 +1,104 @@
+package `in`.sminnovations.smi_attendance_admin.screens.home.ui.componets
+
+import android.annotation.SuppressLint
+import android.util.Log
+import androidx.camera.core.*
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.camera.view.PreviewView
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.OutlinedCard
+import androidx.compose.runtime.*
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.viewinterop.AndroidView
+import androidx.core.content.ContextCompat
+import androidx.lifecycle.LifecycleOwner
+import com.google.mlkit.vision.barcode.BarcodeScannerOptions
+import com.google.mlkit.vision.barcode.BarcodeScanning
+import com.google.mlkit.vision.barcode.common.Barcode
+import com.google.mlkit.vision.common.InputImage
+
+@Composable
+fun QRCodeScannerScreen(
+ onQRCodeScanned: (String) -> Unit,
+ lifecycleOwner: LifecycleOwner = androidx.lifecycle.compose.LocalLifecycleOwner.current
+) {
+ OutlinedCard(
+ modifier = Modifier.padding(10.dp)
+ ) {
+ val context = LocalContext.current
+ val previewView = remember { PreviewView(context) }
+
+ LaunchedEffect(Unit) {
+ val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
+ val cameraProvider = cameraProviderFuture.get()
+
+ val preview = Preview.Builder().build().apply {
+ setSurfaceProvider(previewView.surfaceProvider)
+ }
+
+ val barcodeScanner = BarcodeScanning.getClient(
+ BarcodeScannerOptions.Builder()
+ .setBarcodeFormats(Barcode.FORMAT_QR_CODE)
+ .build()
+ )
+
+ val imageAnalyzer = ImageAnalysis.Builder()
+ .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
+ .build()
+ .also { analyzer ->
+ analyzer.setAnalyzer(ContextCompat.getMainExecutor(context)) { imageProxy ->
+ processImageProxy(imageProxy, barcodeScanner) { value ->
+ onQRCodeScanned(value)
+ }
+ }
+ }
+
+ try {
+ cameraProvider.unbindAll()
+ cameraProvider.bindToLifecycle(
+ lifecycleOwner,
+ CameraSelector.DEFAULT_BACK_CAMERA,
+ preview,
+ imageAnalyzer
+ )
+ } catch (e: Exception) {
+ Log.e("QRCodeScanner", "Camera binding failed", e)
+ }
+ }
+
+ AndroidView(
+ modifier = Modifier
+ .fillMaxWidth()
+ .aspectRatio(1f),
+ factory = { previewView }
+ )
+ }
+}
+
+@SuppressLint("UnsafeOptInUsageError")
+private fun processImageProxy(
+ imageProxy: ImageProxy,
+ scanner: com.google.mlkit.vision.barcode.BarcodeScanner,
+ onQRCodeScanned: (String) -> Unit
+) {
+ val mediaImage = imageProxy.image
+ if (mediaImage != null) {
+ val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees)
+ scanner.process(image)
+ .addOnSuccessListener { barcodes ->
+ barcodes.firstOrNull()?.rawValue?.let { qrCodeValue ->
+ onQRCodeScanned(qrCodeValue)
+ }
+ }
+ .addOnFailureListener {
+ Log.e("QRCodeScanner", "Barcode processing failed", it)
+ }
+ .addOnCompleteListener {
+ imageProxy.close()
+ }
+ } else {
+ imageProxy.close()
+ }
+}
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/componets/RequestPermission.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/componets/RequestPermission.kt
new file mode 100644
index 0000000..1b69fb4
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/ui/componets/RequestPermission.kt
@@ -0,0 +1,27 @@
+package `in`.sminnovations.smi_attendance_admin.screens.home.ui.componets
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import com.google.accompanist.permissions.ExperimentalPermissionsApi
+import com.google.accompanist.permissions.PermissionState
+import com.google.accompanist.permissions.isGranted
+
+@OptIn(ExperimentalPermissionsApi::class)
+@Composable
+fun RequestPermissions(
+ cameraPermissionState: PermissionState,
+ locationPermissionState: PermissionState
+) {
+ LaunchedEffect(cameraPermissionState.status.isGranted, locationPermissionState.status.isGranted) {
+ when {
+ !cameraPermissionState.status.isGranted -> {
+ cameraPermissionState.launchPermissionRequest()
+ }
+ !locationPermissionState.status.isGranted -> {
+ locationPermissionState.launchPermissionRequest()
+ }
+ }
+ }
+
+}
+
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/viewModel/homeVM.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/viewModel/homeVM.kt
new file mode 100644
index 0000000..e28d551
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/home/viewModel/homeVM.kt
@@ -0,0 +1,38 @@
+package `in`.sminnovations.smi_attendance_admin.screens.home.viewModel
+
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+
+class HomeViewModel : ViewModel() {
+ private val _qrCodeValue = MutableStateFlow(null)
+ val qrCodeValue: StateFlow = _qrCodeValue.asStateFlow()
+
+ private val _isScanning = MutableStateFlow(false)
+ val isScanning: StateFlow = _isScanning.asStateFlow()
+
+ fun startScanning() {
+ _isScanning.value = true
+ }
+
+ fun stopScanning() {
+ _isScanning.value = false
+ }
+
+ fun setQRCodeValue(value: String) {
+ viewModelScope.launch {
+ _qrCodeValue.emit(value)
+ stopScanning()
+ }
+ }
+
+ fun getEmployeeData(){
+
+ }
+}
+
+
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/data/LoginData.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/data/LoginData.kt
new file mode 100644
index 0000000..23e48fa
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/data/LoginData.kt
@@ -0,0 +1,7 @@
+package `in`.sminnovations.smi_attendance_admin.screens.login.data
+
+data class LoginData(
+ val id : String ="",
+ val password: String = ""
+)
+
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
new file mode 100644
index 0000000..29ba605
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/data/LoginDataStore.kt
@@ -0,0 +1,54 @@
+package `in`.sminnovations.smi_attendance_admin.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 = dataStore.data.map { preferences ->
+ preferences[LOGIN_ID_KEY] ?: ""
+ }
+
+ val password: Flow = dataStore.data.map { preferences ->
+ preferences[PASSWORD_KEY] ?: ""
+ }
+
+ val isLoggedIn: Flow = 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.remove(LOGIN_ID_KEY)
+ preferences.remove(PASSWORD_KEY)
+ preferences[IS_LOGGED_IN_KEY] = false
+ }
+ }
+}
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
new file mode 100644
index 0000000..d995cb4
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/ui/LoginScreen.kt
@@ -0,0 +1,150 @@
+package `in`.sminnovations.smi_attendance_admin.screens.login.ui
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.aspectRatio
+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.rememberScrollState
+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.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+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.res.painterResource
+import androidx.compose.ui.text.input.PasswordVisualTransformation
+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 androidx.navigation.NavController
+import `in`.sminnovations.smi_attendance_admin.R
+import `in`.sminnovations.smi_attendance_admin.screens.login.ui.components.OutlinedTextFieldWithError
+import `in`.sminnovations.smi_attendance_admin.screens.login.viewModel.LoginViewModel
+import kotlinx.coroutines.launch
+
+@Composable
+fun LoginScreen(
+ navController: NavController,
+ 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))
+ }
+}
+
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
new file mode 100644
index 0000000..9f30d52
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/ui/components/OutlinedTextFiledWithErrors.kt
@@ -0,0 +1,55 @@
+package `in`.sminnovations.smi_attendance_admin.screens.login.ui.components
+
+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)
+ )
+ }
+ }
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..c55ce0b
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/login/viewModel/LoginViewModel.kt
@@ -0,0 +1,113 @@
+package `in`.sminnovations.smi_attendance_admin.screens.login.viewModel
+
+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.smi_attendance_admin.data.dataStore.Employee
+import `in`.sminnovations.smi_attendance_admin.screens.login.data.LoginData
+import `in`.sminnovations.smi_attendance_admin.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
+) : 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 {
+ 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")) {
+ viewModelScope.launch {
+ loginDataStore.saveLoginData(userId, password)
+ _isLoggedIn.value = true
+ onLoginSuccess()
+
+ }
+ } else {
+ _isPasswordError.value = true
+ }
+ }
+ } else {
+ _isIDError.value = true
+ }
+ }.addOnFailureListener {
+ _isIDError.value = true
+ }
+ }
+
+ }
+
+ fun logout() {
+ viewModelScope.launch {
+ loginDataStore.clearLoginData()
+ _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
+ }
+ }
+}
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/Settings.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/Settings.kt
new file mode 100644
index 0000000..9014157
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/Settings.kt
@@ -0,0 +1,46 @@
+package `in`.sminnovations.smi_attendance_admin.screens.settings
+
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.OutlinedCard
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.hilt.navigation.compose.hiltViewModel
+import `in`.sminnovations.smi_attendance_admin.screens.login.viewModel.LoginViewModel
+import `in`.sminnovations.smi_attendance_admin.screens.settings.components.TopComponents
+import `in`.sminnovations.smi_attendance_admin.screens.settings.components.subSetting.AboutSettings
+import `in`.sminnovations.smi_attendance_admin.screens.settings.viewModel.SettingsViewModel
+
+@Composable
+fun SettingsScreen(settingsViewModel: SettingsViewModel = hiltViewModel()) {
+ val context = LocalContext.current
+ val scrollState = rememberScrollState()
+ Column(
+ modifier = Modifier
+ .verticalScroll(scrollState)
+ .fillMaxSize(),
+ ) {
+ Spacer(modifier = Modifier.height(20.dp))
+ TopComponents()
+ Spacer(modifier = Modifier.height(20.dp))
+ OutlinedCard(
+ modifier = Modifier
+ .padding(10.dp)
+ .wrapContentSize()
+ ) {
+ AboutSettings(context = context,settingsViewModel = settingsViewModel)
+
+
+ }
+ }
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..cc47fa9
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/components/TopComponents.kt
@@ -0,0 +1,74 @@
+package `in`.sminnovations.smi_attendance_admin.screens.settings.components
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+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.shape.RoundedCornerShape
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import `in`.sminnovations.smi_attendance_admin.R
+
+
+@Composable
+fun TopComponents(
+) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth(),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Image(
+ painter = painterResource(id = R.drawable.smi_logo), // replace with your image resource
+ contentDescription = "Profile Photo",
+ contentScale = ContentScale.Crop,
+ modifier = Modifier
+ .size(150.dp)
+ .clip(RoundedCornerShape(16.dp))
+ )
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ Text(
+ text = "Sathwik C S",
+ style = MaterialTheme.typography.titleMedium,
+ fontWeight = FontWeight.Bold,
+ fontSize = 20.sp,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+
+ Spacer(modifier = Modifier.height(8.dp))
+
+ Text(
+ text = "ID: 69420",
+ style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ fontSize = 16.sp
+ )
+
+ Spacer(modifier = Modifier.height(4.dp))
+
+ Text(
+ text = "Android Developer",
+ style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.colorScheme.primary,
+ fontSize = 16.sp
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/components/settingsComponents/ClickableCard.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/components/settingsComponents/ClickableCard.kt
new file mode 100644
index 0000000..a67b2fd
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/components/settingsComponents/ClickableCard.kt
@@ -0,0 +1,125 @@
+package `in`.sminnovations.smi_attendance_admin.screens.settings.components.settingsComponents
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.combinedClickable
+import androidx.compose.foundation.indication
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+
+
+
+@Composable
+fun ClickableCard(
+ title:String,
+ subtitle:String,
+ onClick: (Boolean) -> Unit,
+ icon: ImageVector
+) {
+ Row(
+ modifier = Modifier
+// .background(MaterialTheme.colorScheme.surfaceContainer)
+ .clickable{ onClick(true)}
+ .fillMaxWidth()
+ .padding(16.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Icon(
+ imageVector = icon,
+ contentDescription = null,
+ modifier = Modifier.size(24.dp)
+ )
+ Spacer(modifier = Modifier.width(16.dp))
+ Column(
+ modifier = Modifier
+ .weight(1f)
+ ) {
+ Text(
+ text = title,
+ fontWeight = FontWeight.Bold,
+ style = MaterialTheme.typography.bodyLarge,
+ )
+ Text(
+ text = subtitle,
+ style = MaterialTheme.typography.bodyMedium,
+ )
+ }
+ }
+
+}
+
+
+@OptIn( ExperimentalFoundationApi::class)
+@Composable
+fun CombinedClickableCard(
+ title:String,
+ subtitle:String,
+ onClick: (Boolean) -> Unit,
+ onDoubleClick: ((Boolean) -> Unit?)? =null,
+ onLongClick: ((Boolean) -> Unit?)? =null,
+ icon: ImageVector
+) {
+ val interactionSource = remember { MutableInteractionSource() }
+ Row(
+ modifier = Modifier
+// .background(MaterialTheme.colorScheme.surfaceContainer)
+ .combinedClickable (
+ onClick = { onClick(true) },
+ onDoubleClick = {
+ if (onDoubleClick != null) {
+ onDoubleClick(true)
+ }
+ },
+ onLongClick = {
+ if (onLongClick != null) {
+ onLongClick(true)
+ }
+ }
+ )
+ .fillMaxWidth()
+ .padding(16.dp)
+ .indication(interactionSource,null)
+ ,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Icon(
+ imageVector = icon,
+ contentDescription = null,
+ modifier = Modifier.size(24.dp)
+ )
+ Spacer(modifier = Modifier.width(16.dp))
+ Column(
+ modifier = Modifier
+ .weight(1f)
+ ) {
+ Text(
+ text = title,
+ fontWeight = FontWeight.Bold,
+ style = MaterialTheme.typography.bodyLarge,
+ )
+ Text(
+ text = subtitle,
+ style = MaterialTheme.typography.bodyMedium,
+ )
+ }
+ }
+
+}
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/components/subSetting/AboutCard.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/components/subSetting/AboutCard.kt
new file mode 100644
index 0000000..1dfa536
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/components/subSetting/AboutCard.kt
@@ -0,0 +1,91 @@
+package `in`.sminnovations.smi_attendance_admin.screens.settings.components.subSetting
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.widget.Toast
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Button
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.OutlinedCard
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+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.vector.ImageVector
+import androidx.compose.ui.res.vectorResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import `in`.sminnovations.smi_attendance_admin.R
+import `in`.sminnovations.smi_attendance_admin.screens.settings.data.SettingsData
+import `in`.sminnovations.smi_attendance_admin.screens.settings.components.settingsComponents.ClickableCard
+import `in`.sminnovations.smi_attendance_admin.screens.settings.components.settingsComponents.CombinedClickableCard
+import `in`.sminnovations.smi_attendance_admin.screens.settings.viewModel.SettingsViewModel
+import kotlinx.coroutines.launch
+
+
+@SuppressLint("CoroutineCreationDuringComposition")
+@Composable
+fun AboutSettings(context: Context, settingsViewModel : SettingsViewModel)
+{
+ val scope = rememberCoroutineScope()
+ val dataStore = SettingsData(context)
+ var clickCount by remember { mutableIntStateOf(0) }
+ if (clickCount > 5) {
+ scope.launch {
+ dataStore.setDevMode(true)
+ }
+ clickCount = 0
+ Toast.makeText(context, "Developer mode is On : Scroll Down", Toast.LENGTH_SHORT).show()
+ }
+ Column(modifier = Modifier.padding(10.dp,0.dp,10.dp,10.dp)) {
+ Text(
+ text = "About",
+ style = MaterialTheme.typography.labelLarge,
+ fontWeight = FontWeight.Bold,
+ modifier = Modifier
+ .align(Alignment.Start)
+ .padding(14.dp),
+ color = MaterialTheme.colorScheme.primary
+ )
+ OutlinedCard{
+ ClickableCard(
+ title = "Version",
+ subtitle = "1.0.04",
+ onClick = {
+ clickCount++
+ },
+ icon = ImageVector.vectorResource(id = R.drawable.round_info_24)
+
+ )
+ CombinedClickableCard(
+ title = "Developer",
+ subtitle = "SM Innovations Pvt Ltd",
+ onClick = {
+ }, onDoubleClick={
+
+ },
+ icon = ImageVector.vectorResource(id = R.drawable.round_logo_dev_24)
+ )
+ Button(
+ onClick = {
+ settingsViewModel.logout() // Call your logout function from ViewModel
+ },
+ modifier = Modifier
+ .align(Alignment.CenterHorizontally)
+ .padding(top = 16.dp)
+ ) {
+ Text(text = "Logout")
+ }
+
+ }
+ }
+
+
+}
+
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/data/EmployeeData.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/data/EmployeeData.kt
new file mode 100644
index 0000000..260f5fb
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/data/EmployeeData.kt
@@ -0,0 +1,7 @@
+package `in`.sminnovations.smi_attendance_admin.screens.settings.data
+
+class EmployeeDataSettings (
+ val name : String = "",
+ val id : String = "",
+ val designation : String = ""
+)
\ No newline at end of file
diff --git a/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/data/datastore.kt b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/data/datastore.kt
new file mode 100644
index 0000000..a476775
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/data/datastore.kt
@@ -0,0 +1,83 @@
+package `in`.sminnovations.smi_attendance_admin.screens.settings.data
+
+import android.content.Context
+import androidx.datastore.core.DataStore
+import androidx.datastore.preferences.core.Preferences
+import androidx.datastore.preferences.core.booleanPreferencesKey
+import androidx.datastore.preferences.core.edit
+import androidx.datastore.preferences.core.stringPreferencesKey
+import androidx.datastore.preferences.preferencesDataStore
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+
+class SettingsData(private val context: Context) {
+
+ companion object {
+ private val Context.dataStore: DataStore by preferencesDataStore("Settings")
+ val DYNAMIC_THEME_KEY = booleanPreferencesKey("dynamic_theme")
+ val BLACK_THEME_KEY = booleanPreferencesKey("black_theme")
+ val THEME_MODE_KEY = stringPreferencesKey("app_theme")
+ val DEV_MODE_TOGGLE_KEY = booleanPreferencesKey("dev_mode_toggle")
+ }
+
+
+
+ val getDevModeToggle: Flow = context.dataStore.data
+ .map { preferences ->
+ preferences[DEV_MODE_TOGGLE_KEY] ?: false
+ }
+
+ suspend fun setDevMode(mode: Boolean) {
+ context.dataStore.edit { preferences ->
+ preferences[DEV_MODE_TOGGLE_KEY] = mode
+ }
+ }
+
+
+
+
+ val getDynamicColorThemeValue: Flow = context.dataStore.data
+ .map { preferences ->
+ preferences[DYNAMIC_THEME_KEY] ?: true
+ }
+
+ suspend fun setDynamicColorThemeValue(value: Boolean) {
+ context.dataStore.edit { preferences ->
+ preferences[DYNAMIC_THEME_KEY] = value
+ }
+ }
+
+
+
+
+
+
+ val getBlackThemeValue: Flow = context.dataStore.data
+ .map { preferences ->
+ preferences[BLACK_THEME_KEY] ?: false
+ }
+
+ suspend fun setBlackThemeValue(value: Boolean) {
+ context.dataStore.edit { preferences ->
+ preferences[BLACK_THEME_KEY] = value
+ }
+ }
+
+
+
+
+
+ val getThemeMode: Flow = context.dataStore.data
+ .map { preferences ->
+ preferences[THEME_MODE_KEY] ?: "System default"
+ }
+
+ suspend fun saveThemeMode(theme: String) {
+ context.dataStore.edit { preferences ->
+ preferences[THEME_MODE_KEY] = theme
+ }
+ }
+
+
+}
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
new file mode 100644
index 0000000..8e0120d
--- /dev/null
+++ b/app/src/main/java/in/sminnovations/smi_attendance_admin/screens/settings/viewModel/SettingsViewModel.kt
@@ -0,0 +1,29 @@
+package `in`.sminnovations.smi_attendance_admin.screens.settings.viewModel
+
+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.login.data.LoginDataStore
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@HiltViewModel
+class SettingsViewModel @Inject constructor(
+ private val loginDataStore: LoginDataStore,
+ private val firebaseFirestore: FirebaseFirestore
+) : ViewModel() {
+ private val _isLoggedIn = MutableStateFlow(false)
+ val isLoggedIn = _isLoggedIn.asStateFlow()
+
+
+ fun logout() {
+ viewModelScope.launch {
+ loginDataStore.clearLoginData()
+ _isLoggedIn.value = false
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/baseline_close_24.xml b/app/src/main/res/drawable/baseline_close_24.xml
new file mode 100644
index 0000000..f8ca0c6
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_close_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_menu_24.xml b/app/src/main/res/drawable/baseline_menu_24.xml
new file mode 100644
index 0000000..90a85a6
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_menu_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_visibility_24.xml b/app/src/main/res/drawable/baseline_visibility_24.xml
new file mode 100644
index 0000000..f843e29
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_visibility_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/baseline_visibility_off_24.xml b/app/src/main/res/drawable/baseline_visibility_off_24.xml
new file mode 100644
index 0000000..5993ca3
--- /dev/null
+++ b/app/src/main/res/drawable/baseline_visibility_off_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/round_auto_mode_24.xml b/app/src/main/res/drawable/round_auto_mode_24.xml
new file mode 100644
index 0000000..ded3ee5
--- /dev/null
+++ b/app/src/main/res/drawable/round_auto_mode_24.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/round_color_lens_24.xml b/app/src/main/res/drawable/round_color_lens_24.xml
new file mode 100644
index 0000000..2f0ecdf
--- /dev/null
+++ b/app/src/main/res/drawable/round_color_lens_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/round_contrast_24.xml b/app/src/main/res/drawable/round_contrast_24.xml
new file mode 100644
index 0000000..fe34a64
--- /dev/null
+++ b/app/src/main/res/drawable/round_contrast_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/round_delete_sweep_24.xml b/app/src/main/res/drawable/round_delete_sweep_24.xml
new file mode 100644
index 0000000..0b63d04
--- /dev/null
+++ b/app/src/main/res/drawable/round_delete_sweep_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/round_developer_mode_24.xml b/app/src/main/res/drawable/round_developer_mode_24.xml
new file mode 100644
index 0000000..2b7442f
--- /dev/null
+++ b/app/src/main/res/drawable/round_developer_mode_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/round_info_24.xml b/app/src/main/res/drawable/round_info_24.xml
new file mode 100644
index 0000000..3218106
--- /dev/null
+++ b/app/src/main/res/drawable/round_info_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/round_logo_dev_24.xml b/app/src/main/res/drawable/round_logo_dev_24.xml
new file mode 100644
index 0000000..a65322b
--- /dev/null
+++ b/app/src/main/res/drawable/round_logo_dev_24.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/round_translate_24.xml b/app/src/main/res/drawable/round_translate_24.xml
new file mode 100644
index 0000000..23fbbb0
--- /dev/null
+++ b/app/src/main/res/drawable/round_translate_24.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/smi_logo.png b/app/src/main/res/drawable/smi_logo.png
new file mode 100644
index 0000000..e3e2ea6
Binary files /dev/null and b/app/src/main/res/drawable/smi_logo.png differ
diff --git a/build.gradle.kts b/build.gradle.kts
index f74b04b..4d03a81 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -2,4 +2,6 @@
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.jetbrains.kotlin.android) apply false
-}
\ No newline at end of file
+ id("com.google.dagger.hilt.android") version "2.51.1" apply false
+ id("com.google.gms.google-services") version "4.4.2" apply false
+}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 6e160a8..d60bb8d 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -8,6 +8,8 @@ espressoCore = "3.6.1"
lifecycleRuntimeKtx = "2.8.6"
activityCompose = "1.9.2"
composeBom = "2024.04.01"
+datastoreCoreAndroid = "1.1.1"
+datastorePreferencesCoreJvm = "1.1.1"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -24,6 +26,8 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
+androidx-datastore-core-android = { group = "androidx.datastore", name = "datastore-core-android", version.ref = "datastoreCoreAndroid" }
+androidx-datastore-preferences-core-jvm = { group = "androidx.datastore", name = "datastore-preferences-core-jvm", version.ref = "datastorePreferencesCoreJvm" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }