diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index a2ba9de45474f1ed05f1c6bb2728fbdb9fe5a4b2..98d6324f346c31eee2617a646fcb4434c88e6b94 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -54,6 +54,8 @@ dependencies {
     implementation("com.squareup.retrofit2:retrofit:2.9.0")
     implementation("com.squareup.retrofit2:converter-gson:2.9.0")
     implementation("androidx.security:security-crypto:1.1.0-alpha06")
+    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1")
+    implementation(libs.androidx.work.runtime.ktx)
     implementation("androidx.compose.runtime:runtime-livedata:1.0.5")
     implementation("androidx.compose.runtime:runtime-rxjava2:1.0.5")
     testImplementation(libs.junit)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 64e5c24018e439a5978975325a27bd63e128ff18..72f59002fb490e159c507aa07c93c11c4d305b79 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,8 +1,14 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools">
+
+    <uses-feature
+        android:name="android.hardware.camera"
+        android:required="false" />
+
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.CAMERA" />
 
 
     <application
diff --git a/app/src/main/java/com/example/myapplication/LoginActivity.kt b/app/src/main/java/com/example/myapplication/LoginActivity.kt
index eb150605a39b97c79bc2ab651ae5deb0018b5503..43631724f07aa70428cf4f4dc85077a6c7547f9c 100644
--- a/app/src/main/java/com/example/myapplication/LoginActivity.kt
+++ b/app/src/main/java/com/example/myapplication/LoginActivity.kt
@@ -9,11 +9,12 @@ import androidx.appcompat.app.AppCompatActivity
 import com.example.myapplication.databinding.ActivityLoginBinding
 import com.example.myapplication.repository.AuthRepository
 import com.example.myapplication.ui.login.UserViewModel
+import com.example.myapplication.util.EventBus
 import com.example.myapplication.util.LoginListener
 import com.example.myapplication.util.SecretPreference
 import com.example.myapplication.NetworkConnection
 
-class LoginActivity : AppCompatActivity() , LoginListener {
+class LoginActivity : AppCompatActivity() {
 
     private lateinit var binding: ActivityLoginBinding
     private var userViewModel : UserViewModel = UserViewModel()
@@ -24,7 +25,7 @@ class LoginActivity : AppCompatActivity() , LoginListener {
         super.onCreate(savedInstanceState)
 
         secretPreference = SecretPreference(this)
-        authRepository = AuthRepository(this, secretPreference)
+        authRepository = AuthRepository(secretPreference)
 
         binding = ActivityLoginBinding.inflate(layoutInflater)
         setContentView(binding.root)
@@ -39,9 +40,17 @@ class LoginActivity : AppCompatActivity() , LoginListener {
             authRepository.loginRequest(binding.emailInput.text.toString(), binding.passwordInput.text.toString())
             Log.d("Development", "Activity: Login request sent")
         }
+
+        EventBus.subscribe("LOGIN_SUCCESS") {
+            onLoginSuccess()
+        }
+
+        EventBus.subscribe("LOGIN_FAIL") {
+            onLoginFailure()
+        }
     }
 
-    override fun onLoginSuccess() {
+    fun onLoginSuccess() {
         userViewModel.setUser(binding.emailInput.text.toString(), binding.passwordInput.text.toString())
         Log.d("Development", "Activity: Login success")
         val preference : SharedPreferences = getSharedPreferences("secret_shared_prefs", MODE_PRIVATE)
@@ -49,7 +58,7 @@ class LoginActivity : AppCompatActivity() , LoginListener {
         finish()
     }
 
-    override fun onLoginFailure() {
+    fun onLoginFailure() {
         Log.d("Development", "Activity: Login failed")
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/example/myapplication/MainActivity.kt b/app/src/main/java/com/example/myapplication/MainActivity.kt
index 374cf18e61144d05c4f6cf3353f4b9a0283b6bd7..0c698b0fa4960e26ebcfd5a6c288d312efd41749 100644
--- a/app/src/main/java/com/example/myapplication/MainActivity.kt
+++ b/app/src/main/java/com/example/myapplication/MainActivity.kt
@@ -1,11 +1,11 @@
 package com.example.myapplication
 
-import android.app.AlertDialog
-import android.content.Context
 import android.content.Intent
-import android.net.ConnectivityManager
-import android.net.NetworkCapabilities
+import android.net.Uri
 import android.os.Bundle
+import android.view.LayoutInflater
+import android.widget.Button
+import android.widget.EditText
 import com.google.android.material.bottomnavigation.BottomNavigationView
 import androidx.appcompat.app.AppCompatActivity
 import androidx.lifecycle.MutableLiveData
@@ -14,11 +14,18 @@ import androidx.navigation.findNavController
 import androidx.navigation.ui.AppBarConfiguration
 import androidx.navigation.ui.setupActionBarWithNavController
 import androidx.navigation.ui.setupWithNavController
+import androidx.work.PeriodicWorkRequestBuilder
+import androidx.work.WorkManager
 import com.example.myapplication.databinding.ActivityMainBinding
+import com.example.myapplication.service.TokenExpiryWorker
+import com.example.myapplication.util.EventBus
+import com.example.myapplication.util.SecretPreference
+import java.util.concurrent.TimeUnit
 import com.example.myapplication.ui.settings.SettingsViewModel
 
-class MainActivity : AppCompatActivity() {
+class MainActivity : AppCompatActivity(){
     private lateinit var binding: ActivityMainBinding
+    private lateinit var secretPreference : SecretPreference
     private val checkConnection by lazy { CheckConnection(application) }
     private val connected : MutableLiveData<Boolean> = MutableLiveData(true)
     private lateinit var viewModelSettings: SettingsViewModel
@@ -43,21 +50,14 @@ class MainActivity : AppCompatActivity() {
         setupActionBarWithNavController(navController, appBarConfiguration)
         navView.setupWithNavController(navController)
 
-        viewModelSettings = ViewModelProvider(this).get(SettingsViewModel::class.java)
+        val isOnline : String = if (isOnline()) "Online" else "Offline"
+        Log.i("Development", "Online Connectivity Status: $isOnline")
 
-        val connectionLostBuilder: AlertDialog.Builder = AlertDialog.Builder(this)
-        connectionLostBuilder
-            .setMessage("Connection lost")
-            .setTitle("There is no internet connection")
-
-        if (!isOnline()) {
-            updateConnection(false)
-        } else {
-            updateConnection(true)
-        }
 
         val loginIntent = Intent(this, LoginActivity::class.java)
         startActivity(loginIntent)
+
+
     }
 
     override fun onResume() {
@@ -85,6 +85,19 @@ class MainActivity : AppCompatActivity() {
 
     fun getConnectionStatus(): Boolean {
         return connected.value == true
+
+        // CHECK TOKEN for expiry
+        val backgroundWork = PeriodicWorkRequestBuilder<TokenExpiryWorker>(15, TimeUnit.MINUTES).build()
+        WorkManager.getInstance(this).enqueue(backgroundWork)
+
+        // event listener for token expiry
+        EventBus.subscribe("TOKEN_EXPIRED") {
+            Log.i("Development", "Token expired")
+            secretPreference = SecretPreference(this)
+            secretPreference.clearToken()
+            val loginIntent = Intent(this, LoginActivity::class.java)
+            startActivity(loginIntent)
+        }
     }
 
     private fun isOnline(): Boolean {
diff --git a/app/src/main/java/com/example/myapplication/backendconnect/BackendService.kt b/app/src/main/java/com/example/myapplication/backendconnect/BackendService.kt
index fa10fd0b88a21d86796bdb4df5dfde4c80c5ec6f..3d2a0819d409cfafeed7d6f485087855eccaf8c3 100644
--- a/app/src/main/java/com/example/myapplication/backendconnect/BackendService.kt
+++ b/app/src/main/java/com/example/myapplication/backendconnect/BackendService.kt
@@ -2,18 +2,24 @@ package com.example.myapplication.backendconnect
 
 import com.example.myapplication.model.auth.Token
 import com.example.myapplication.model.auth.UserCred
+import com.example.myapplication.model.bill.BillResponse
+import okhttp3.MultipartBody
 import retrofit2.Call
 import retrofit2.http.Body
+import retrofit2.http.Header
+import retrofit2.http.Multipart
 import retrofit2.http.POST
+import retrofit2.http.Part
 
 
 interface BackendService {
     @POST("auth/login")
-    fun login(@Body userCred: UserCred): Call<Token>
+    fun login(@Body data: Map<String, String>): Call<Token>
 
     @POST("auth/token")
-    fun tokenCheck(@Body token: Token): Call<Token>
+    fun tokenCheck(@Header("Authorization") token : String): Call<UserCred>
 
-//    @POST("bill/upload")
-//    fun uploadBill(@Body bill: Bill): Call<BillResponse>
+    @Multipart
+    @POST("bill/upload")
+    fun uploadBill(@Header("Authorization") token: String , @Part file: MultipartBody.Part): Call<BillResponse>
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/example/myapplication/model/auth/UserCred.kt b/app/src/main/java/com/example/myapplication/model/auth/UserCred.kt
index c46eb7c1d95418954d00efb8464c9b49f265f63d..5fcf2595515bcef81bb54866d97c771c384674e5 100644
--- a/app/src/main/java/com/example/myapplication/model/auth/UserCred.kt
+++ b/app/src/main/java/com/example/myapplication/model/auth/UserCred.kt
@@ -3,8 +3,10 @@ package com.example.myapplication.model.auth
 import com.google.gson.annotations.SerializedName
 
 data class UserCred (
-    @SerializedName("email")
-    val email: String,
-    @SerializedName("password")
-    val password: String
+    @SerializedName("nim")
+    val nim: String,
+    @SerializedName("iat")
+    val iat: String,
+    @SerializedName("exp")
+    val exp: String
     )
\ No newline at end of file
diff --git a/app/src/main/java/com/example/myapplication/model/bill/BillResponse.kt b/app/src/main/java/com/example/myapplication/model/bill/BillResponse.kt
new file mode 100644
index 0000000000000000000000000000000000000000..0121273f246c13f23b88512d39803b8e0cc41247
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/model/bill/BillResponse.kt
@@ -0,0 +1,22 @@
+package com.example.myapplication.model.bill
+
+import com.google.gson.annotations.SerializedName
+
+data class BillResponse (
+    @SerializedName("items")
+    val items: Items
+) {
+    data class Items (
+        @SerializedName("items")
+        val items: List<Item>
+    ) {
+        data class Item (
+            @SerializedName("name")
+            val name: String,
+            @SerializedName("qty")
+            val quantity: Int,
+            @SerializedName("price")
+            val price: Double
+        )
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/myapplication/repository/AuthRepository.kt b/app/src/main/java/com/example/myapplication/repository/AuthRepository.kt
index 139f5ad9618c67254bbe83e49f8acac7f48657c7..f519451746e7fce29eb1fb827a8dc6db7669c8bd 100644
--- a/app/src/main/java/com/example/myapplication/repository/AuthRepository.kt
+++ b/app/src/main/java/com/example/myapplication/repository/AuthRepository.kt
@@ -1,23 +1,32 @@
 package com.example.myapplication.repository
 
-import android.content.Context
+import android.net.Uri
 import android.util.Log
+import androidx.core.content.ContentProviderCompat.requireContext
 import com.example.myapplication.backendconnect.Client
 import com.example.myapplication.model.auth.Token
 import com.example.myapplication.model.auth.UserCred
+import com.example.myapplication.model.bill.BillResponse
+import com.example.myapplication.util.EventBus
 import com.example.myapplication.util.LoginListener
 import com.example.myapplication.util.SecretPreference
+import okhttp3.MediaType
+import okhttp3.MultipartBody
+import okhttp3.RequestBody
+
 import retrofit2.Call
 import retrofit2.Callback
 import retrofit2.Response
+import java.io.File
+import java.io.FileInputStream
+import java.io.FileOutputStream
 
 class AuthRepository (
-    private val loginListener: LoginListener,
     private val secretPreference: SecretPreference) {
 
     fun loginRequest(email: String, password: String){
         Log.d("Development", "Login request to backend service")
-        Client.connect.login(UserCred(email, password)).enqueue(
+        Client.connect.login(mapOf("email" to email, "password" to password)).enqueue(
             object : Callback<Token> {
                 override fun onResponse(call: Call<Token>, response: Response<Token>) {
                     Log.d("Development", "Response: ${response.body()}")
@@ -29,19 +38,80 @@ class AuthRepository (
                         secretPreference.saveToken(token?.token ?: "")
 
                         // callback the loginActivity
-                        loginListener.onLoginSuccess()
+                        //loginListener.onLoginSuccess()
+                        EventBus.publish("LOGIN_SUCCESS")
 
                     } else {
                         Log.d("Development", "LOGIN FAILED, http code : ${response.code()}")
-                        loginListener.onLoginFailure()
+                        //loginListener.onLoginFailure()
+                        EventBus.publish("LOGIN_FAIL")
                     }
                 }
 
                 override fun onFailure(call: Call<Token>, t: Throwable) {
                     Log.d("Development", "LOGIN FAILED, error on delivery : ${t.message}")
-                    loginListener.onLoginFailure()
+//                    loginListener.onLoginFailure()
+                    EventBus.publish("LOGIN_FAIL")
+                }
+            }
+        )
+    }
+
+    fun tokenCheckRequest() {
+        Log.d("Development", "Token check request to backend service")
+        val token = secretPreference.getToken() ?: ""
+
+        Client.connect.tokenCheck("Bearer $token").enqueue(
+            object : Callback<UserCred> {
+                override fun onResponse(call: Call<UserCred>, response: Response<UserCred>) {
+                    Log.d("Development", "Response: ${response.body()}")
+                    if (response.isSuccessful) {
+                        Log.d("Development", "Token check success: Valid token")
+                    }
+                    else if (response.code() == 401) {
+                        Log.d("Development", "Token check failed: Invalid token or expired")
+                        EventBus.publish("TOKEN_EXPIRED")
+                    }
+                    else {
+                        Log.d("Development", "TOKEN CHECK FAILED, http code : ${response.code()}")
+                        EventBus.publish("TOKEN_EXPIRED")
+                    }
+                }
+
+                override fun onFailure(call: Call<UserCred>, t: Throwable) {
+                    Log.d("Development", "TOKEN CHECK FAILED, error on delivery : ${t.message}")
                 }
             }
         )
     }
+
+    fun uploadBillRequest(file: File) {
+        Log.d("Development", "Upload bill request to backend service")
+
+        val token : String = secretPreference.getToken() ?: ""
+        val requestFile = RequestBody.create(MediaType.parse("image/jpeg"), file)
+        val body = MultipartBody.Part.createFormData("file", file.name, requestFile)
+
+        Client.connect.uploadBill("Bearer $token", body).enqueue(
+            object : Callback<BillResponse> {
+                override fun onResponse(call: Call<BillResponse>, response: Response<BillResponse>) {
+                    Log.d("Development", "Response: $response")
+                    if (response.isSuccessful) {
+                        Log.i("Development", "Upload Success, response: ${response.body()}")
+                        EventBus.publish("UPLOAD_SUCCESS")
+                    } else {
+                        Log.d("Development", "UPLOAD FAILED, http code : ${response.code()}")
+                        EventBus.publish("UPLOAD_FAIL")
+                    }
+                }
+
+                override fun onFailure(call: Call<BillResponse>, t: Throwable) {
+                    Log.d("Development", "UPLOAD FAILED, error on delivery : ${t.message}")
+                    EventBus.publish("UPLOAD_FAIL")
+                }
+            }
+        )
+    }
+
+
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/example/myapplication/service/TokenExpiryWorker.kt b/app/src/main/java/com/example/myapplication/service/TokenExpiryWorker.kt
new file mode 100644
index 0000000000000000000000000000000000000000..3b6548d6386626d9c9cafa7584f2577676b8ea2a
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/service/TokenExpiryWorker.kt
@@ -0,0 +1,23 @@
+package com.example.myapplication.service
+
+import android.content.Context
+import android.util.Log
+import androidx.work.CoroutineWorker
+import androidx.work.WorkerParameters
+import com.example.myapplication.repository.AuthRepository
+import com.example.myapplication.util.LoginListener
+import com.example.myapplication.util.SecretPreference
+
+class TokenExpiryWorker (appContext: Context, workerParams: WorkerParameters)
+    : CoroutineWorker(appContext, workerParams) {
+
+    private val secretPreference = SecretPreference(applicationContext)
+    private val authRepository = AuthRepository(secretPreference)
+
+    override suspend fun doWork(): Result {
+        Log.i("Development", "Token expiry worker started")
+        authRepository.tokenCheckRequest()
+        return Result.success()
+    }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/myapplication/ui/dashboard/DashboardFragment.kt b/app/src/main/java/com/example/myapplication/ui/dashboard/DashboardFragment.kt
index e417b48167f5c10e3e10ab5aacd415be5730a1fd..8258269c19efd914decbcc2cf49a0aee3d703cce 100644
--- a/app/src/main/java/com/example/myapplication/ui/dashboard/DashboardFragment.kt
+++ b/app/src/main/java/com/example/myapplication/ui/dashboard/DashboardFragment.kt
@@ -1,22 +1,102 @@
 package com.example.myapplication.ui.dashboard
 
+import android.Manifest
+import android.annotation.SuppressLint
+import android.content.ActivityNotFoundException
+import android.content.ContentValues
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.graphics.ImageFormat
+import android.graphics.SurfaceTexture
+import android.hardware.camera2.CameraCaptureSession
+import android.hardware.camera2.CameraDevice
+import android.hardware.camera2.CameraManager
+import android.hardware.camera2.CaptureRequest
+import android.hardware.camera2.params.OutputConfiguration
+import android.hardware.camera2.params.SessionConfiguration
+import android.media.ImageReader
+import android.net.Uri
 import android.os.Bundle
+import android.provider.MediaStore
+import android.util.Log
 import android.view.LayoutInflater
+import android.view.Surface
+import android.view.TextureView
 import android.view.View
 import android.view.ViewGroup
-import android.widget.TextView
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.core.content.ContextCompat
 import androidx.fragment.app.Fragment
 import androidx.lifecycle.ViewModelProvider
-import com.example.myapplication.databinding.FragmentDashboardBinding
+import com.example.myapplication.databinding.FragmentScanBinding
+import com.example.myapplication.repository.AuthRepository
+import com.example.myapplication.util.SecretPreference
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import java.io.File
+import java.io.FileInputStream
+import java.io.FileOutputStream
+import java.util.concurrent.Executor
 
 class DashboardFragment : Fragment() {
 
-    private var _binding: FragmentDashboardBinding? = null
+    private var _binding: FragmentScanBinding? = null
 
     // This property is only valid between onCreateView and
     // onDestroyView.
     private val binding get() = _binding!!
 
+    private lateinit var cameraId: String
+    private lateinit var cameraDevice: CameraDevice
+    private lateinit var captureRequestBuilder : CaptureRequest.Builder
+    private lateinit var mainExecutor : Executor
+    private var cameraPermission: Boolean = false
+    private lateinit var fileImage: File
+    private lateinit var imagePath : String
+
+    private lateinit var authRepository : AuthRepository
+
+    private val stateCallBack = object : CameraDevice.StateCallback() {
+        override fun onOpened(camera: CameraDevice) {
+            cameraDevice = camera
+            startCamera()
+        }
+
+        override fun onDisconnected(camera: CameraDevice) {
+            cameraDevice.close()
+        }
+
+        override fun onError(camera: CameraDevice, error: Int) {
+            cameraDevice.close()
+        }
+    }
+
+    private val surfaceTextureListener = object : TextureView.SurfaceTextureListener {
+        override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
+            Log.i("Development", "Surface texture available")
+            startCamera()
+        }
+
+        override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {
+            // Ignored, Camera does all the work for us
+        }
+
+        override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
+            return false
+        }
+
+        override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {
+            // Ignored
+        }
+    }
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        authRepository = AuthRepository(SecretPreference(requireContext()))
+    }
+
     override fun onCreateView(
         inflater: LayoutInflater,
         container: ViewGroup?,
@@ -25,18 +105,216 @@ class DashboardFragment : Fragment() {
         val dashboardViewModel =
             ViewModelProvider(this).get(DashboardViewModel::class.java)
 
-        _binding = FragmentDashboardBinding.inflate(inflater, container, false)
-        val root: View = binding.root
+        _binding = FragmentScanBinding.inflate(inflater, container, false)
 
-        val textView: TextView = binding.textDashboard
-        dashboardViewModel.text.observe(viewLifecycleOwner) {
-            textView.text = it
+        cameraPermissionCheck()
+
+        binding.buttonScan.setOnClickListener {
+            takePicture()
+        }
+
+        binding.buttonSend.setOnClickListener {
+            if(::imagePath.isInitialized) {
+                CoroutineScope(Dispatchers.IO).launch {
+                    val uri = Uri.parse(imagePath)
+                    val parcelFileDescriptor = requireContext().contentResolver.openFileDescriptor(uri, "r")
+                    val file = File.createTempFile("upload", null, requireContext().cacheDir)
+                    val inputStream = FileInputStream(parcelFileDescriptor?.fileDescriptor)
+                    val outputStream = FileOutputStream(file)
+                    inputStream.copyTo(outputStream)
+
+                    authRepository.uploadBillRequest(file)
+
+                    parcelFileDescriptor?.close()
+                }
+            } else {
+                Log.w("Development", "Image path not initialized")
+            }
+        }
+
+        return binding.root
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        fileImage = File(requireContext().externalMediaDirs.first(), "\"${System.currentTimeMillis()}.jpg\"" )
+    }
+
+    override fun onResume() {
+        super.onResume()
+        if(cameraPermission) {
+            setupCamera()
+            binding.cameraPreview.surfaceTextureListener = surfaceTextureListener
         }
-        return root
     }
 
     override fun onDestroyView() {
         super.onDestroyView()
         _binding = null
     }
+
+    // CAMERA
+    private fun cameraPermissionCheck() {
+        Log.i("Development", "Checking camera permission")
+        if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)
+            == PackageManager.PERMISSION_DENIED) {
+            registerForActivityResult(
+                ActivityResultContracts.RequestPermission()
+            ) { isGranted: Boolean ->
+                if (isGranted) {
+                    // Permission is granted
+                    Log.i("Development", "Camera permission granted")
+                    cameraPermission = true
+                } else {
+                    // Permission is denied
+                    Log.w("Development", "Camera permission DENIED")
+                }
+            }.launch(Manifest.permission.CAMERA)
+
+        } else {
+            cameraPermission = true
+        }
+
+        if(cameraPermission) {
+            Log.i("Development", "Camera permission granted")
+        }
+    }
+
+    private fun setupCamera() {
+        Log.i("Development", "Setting up camera")
+        if(ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)
+            == PackageManager.PERMISSION_GRANTED) {
+            val cameraManager =
+                requireContext().getSystemService(Context.CAMERA_SERVICE) as CameraManager
+            cameraId = cameraManager.cameraIdList[0]
+            Log.i("Development", "Camera ID: $cameraId")
+            cameraManager.openCamera(cameraId, stateCallBack, null)
+            Log.i("Development", "Camera opened")
+        }
+    }
+    @SuppressLint("Recycle")
+    private fun startCamera() {
+        val texture = binding.cameraPreview.surfaceTexture
+        if (texture != null) {
+            texture.setDefaultBufferSize(290, 420)
+        } else {
+            Log.e("Development", "Texture is null")
+        }
+        Log.i("Development", "Camera starting")
+
+        val surface = Surface(texture)
+        captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
+        captureRequestBuilder.addTarget(surface)
+
+        cameraDevice.createCaptureSession(listOf(surface), object : CameraCaptureSession.StateCallback() {
+            override fun onConfigured(session: CameraCaptureSession) {
+                session.setRepeatingRequest(captureRequestBuilder.build(), null, null)
+            }
+
+            override fun onConfigureFailed(session: CameraCaptureSession) {
+                Log.w("Development", "Camera configuration failed")
+            }
+        }, null)
+
+//        val outputConfig : OutputConfiguration = OutputConfiguration(surface)
+//        mainExecutor = ContextCompat.getMainExecutor(requireContext())
+//
+//        val sessionConfig : SessionConfiguration = SessionConfiguration(
+//            SessionConfiguration.SESSION_REGULAR,
+//            listOf(outputConfig),
+//            mainExecutor,
+//            cameraCaptureStateCallback)
+//
+//        cameraDevice.createCaptureSession(sessionConfig)
+
+    }
+
+    val REQUEST_IMAGE_CAPTURE = 1
+
+    private fun dispatchTakePictureIntent() {
+        val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
+        try {
+            startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
+        } catch (e: ActivityNotFoundException) {
+            // display error state to the user
+        }
+    }
+
+
+    private fun takePicture() {
+        val captureRequestBuilderTake = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
+        val imageReader = ImageReader.newInstance(290, 420, ImageFormat.JPEG, 1)
+
+        imageReader.setOnImageAvailableListener({ reader ->
+            Log.i("Development", "image listener called")
+            reader.acquireNextImage().use { image ->
+                val buffer = image.planes[0].buffer
+                val bytes = ByteArray(buffer.remaining())
+                buffer.get(bytes)
+                saveImage(bytes)
+                Log.i("Development", "Image saved")
+            }
+        }, null)
+
+
+        captureRequestBuilderTake.addTarget(imageReader.surface)
+        captureRequestBuilderTake.addTarget(Surface(binding.cameraPreview.surfaceTexture))
+
+        val outputConfig = OutputConfiguration(Surface(binding.cameraPreview.surfaceTexture))
+        val outputConfigReader = OutputConfiguration(imageReader.surface)
+
+        val sessionConfig = SessionConfiguration(SessionConfiguration.SESSION_REGULAR,
+            listOf(outputConfig, outputConfigReader), ContextCompat.getMainExecutor(requireContext()), object : CameraCaptureSession.StateCallback() {
+                override fun onConfigured(session: CameraCaptureSession) {
+                    session.capture(captureRequestBuilderTake.build(), null, null)
+                }
+
+                override fun onConfigureFailed(session: CameraCaptureSession) {
+                    Log.e("Development", "Capture session configuration failed")
+                }
+            })
+
+        cameraDevice.createCaptureSession(sessionConfig)
+    }
+
+    private fun saveImage(file: ByteArray) {
+        val resolver = requireContext().contentResolver
+        val contentValues = ContentValues().apply {
+            put(MediaStore.MediaColumns.DISPLAY_NAME, "Image_${System.currentTimeMillis()}.jpg")
+            put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
+            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
+                put(MediaStore.MediaColumns.IS_PENDING, 1)
+            }
+        }
+
+        val uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
+
+        uri?.let {
+            resolver.openOutputStream(it)?.use { outputStream ->
+                outputStream.write(file)
+            }
+
+            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
+                contentValues.clear()
+                contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0)
+                resolver.update(uri, contentValues, null, null)
+
+            }
+            imagePath = it.toString()
+            Log.i("Development", "Image saved to $it")
+        }
+
+    }
+
+
+    val cameraCaptureStateCallback = object : CameraCaptureSession.StateCallback() {
+        override fun onConfigured(session: CameraCaptureSession) {
+            session.setRepeatingRequest(captureRequestBuilder.build(), null, null)
+        }
+
+        override fun onConfigureFailed(session: CameraCaptureSession) {
+            Log.w("Development", "Camera configuration failed")
+        }
+    }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/example/myapplication/util/EventBus.kt b/app/src/main/java/com/example/myapplication/util/EventBus.kt
new file mode 100644
index 0000000000000000000000000000000000000000..a3b8bb06f325991835b7b0fd00dfa89befe902b3
--- /dev/null
+++ b/app/src/main/java/com/example/myapplication/util/EventBus.kt
@@ -0,0 +1,28 @@
+package com.example.myapplication.util
+
+import android.util.Log
+
+object EventBus {
+
+    private var listeners: MutableMap<String, MutableList<() -> Unit>> = mutableMapOf()
+
+    fun subscribe(event: String, listener: () -> Unit) {
+        if (listeners.containsKey(event)) {
+            // add a new listener to an existing event
+            listeners[event]?.add(listener)
+        } else {
+            // add a new event with a new listener
+            listeners[event] = mutableListOf(listener)
+        }
+    }
+
+    fun publish(event: String) {
+        if (listeners.containsKey(event)) {
+            // call all listeners for the event
+            listeners[event]?.forEach { it() }
+        } else {
+            // no listeners for the event
+            Log.d("Development","No listeners for event: $event")
+        }
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/myapplication/util/SecretPreference.kt b/app/src/main/java/com/example/myapplication/util/SecretPreference.kt
index e0fd205f8288888970b764b9cbc80732e2388b7d..8569b03b5d2391629dafa9ff5a274ca3784bc677 100644
--- a/app/src/main/java/com/example/myapplication/util/SecretPreference.kt
+++ b/app/src/main/java/com/example/myapplication/util/SecretPreference.kt
@@ -25,4 +25,9 @@ class SecretPreference (private val context: Context) {
 
     fun getToken(): String? = sharedPreferences.getString("token", null)
 
+    fun clearToken(){
+        sharedPreferences.edit().remove("token").apply()
+        Log.i("Development", "Token cleared")
+    }
+
 }
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_scan.xml b/app/src/main/res/layout/fragment_scan.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5901b3252192ff780eabb16591041da6ddc2f80b
--- /dev/null
+++ b/app/src/main/res/layout/fragment_scan.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <TextureView
+        android:id="@+id/camera_preview"
+        android:layout_width="290dp"
+        android:layout_height="420dp"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_bias="0.311" />
+
+    <Button
+        android:id="@+id/button_scan"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="20dp"
+        android:text="Capture"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.315"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@id/camera_preview" />
+
+    <Button
+        android:id="@+id/button_send"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Send"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.254"
+        app:layout_constraintStart_toEndOf="@id/button_scan"
+        app:layout_constraintTop_toBottomOf="@id/camera_preview"
+        app:layout_constraintVertical_bias="0.12" />
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 2a937b35557de4690764cd6b2547db0d9aafc2d0..8d5a450e74d343773a514fda3cb1a1bbbdc7efc1 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -13,6 +13,7 @@ lifecycleLivedataKtx = "2.7.0"
 lifecycleViewmodelKtx = "2.7.0"
 navigationFragmentKtx = "2.6.0"
 navigationUiKtx = "2.6.0"
+workRuntimeKtx = "2.9.0"
 
 [libraries]
 android-gif-drawable = { module = "pl.droidsonroids.gif:android-gif-drawable", version.ref = "androidGifDrawable" }
@@ -27,6 +28,7 @@ androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecy
 androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
 androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigationFragmentKtx" }
 androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtx" }
+androidx-work-runtime-ktx = { group = "androidx.work", name = "work-runtime-ktx", version.ref = "workRuntimeKtx" }
 
 [plugins]
 androidApplication = { id = "com.android.application", version.ref = "agp" }