diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 2ee2962cb09d26470512fe163883f2bd43f8a553..cbf15dec27d23379f24fbf910881a32c5b8bc9c9 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -54,11 +54,15 @@ dependencies {
     implementation(libs.androidx.retrofit.gson)
     implementation(libs.poi)
     implementation(libs.poi.ooxml)
-    implementation(libs.androidx.activity)
-    implementation(libs.play.services.location)
     implementation(libs.camera.core)
     implementation(libs.camera.lifecycle)
     implementation(libs.camera.view)
+    implementation(libs.glide)
+    annotationProcessor(libs.glideCompiler)
+    implementation(libs.androidx.activity)
+    implementation(libs.play.services.location)
+    implementation(libs.okhttp)
+    implementation(libs.logging.interceptor)
     annotationProcessor(libs.androidx.room.compiler)
     kapt(libs.androidx.room.compiler)
     implementation(libs.androidx.legacy.support.v4)
diff --git a/app/src/main/java/com/example/abe/MainActivity.kt b/app/src/main/java/com/example/abe/MainActivity.kt
index e0b9c7d5de845c43a164e52fde42fb089d274afb..9a09b4bb1ea3d304de725d64f039420b8466369a 100644
--- a/app/src/main/java/com/example/abe/MainActivity.kt
+++ b/app/src/main/java/com/example/abe/MainActivity.kt
@@ -94,8 +94,9 @@ class MainActivity : AppCompatActivity(), ExportAlertDialogFragment.ExportAlertD
         appBarConfiguration = AppBarConfiguration(
             setOf(
                 R.id.navigation_transactions,
+                R.id.navigation_graph,
                 R.id.navigation_settings,
-                R.id.navigation_graph
+                R.id.navigation_scan
             )
         )
         setupActionBarWithNavController(navController, appBarConfiguration)
diff --git a/app/src/main/java/com/example/abe/data/network/Retrofit.kt b/app/src/main/java/com/example/abe/data/network/Retrofit.kt
index 992568b5827e4826620040170b84655550e69947..fe589397ae144b2cd8e8805ab8053fc31301d6aa 100644
--- a/app/src/main/java/com/example/abe/data/network/Retrofit.kt
+++ b/app/src/main/java/com/example/abe/data/network/Retrofit.kt
@@ -1,20 +1,33 @@
 package com.example.abe.data.network
 
 import android.content.Context
-import android.preference.PreferenceManager
+import android.util.Log
 import com.example.abe.R
-import com.example.abe.services.AuthService
+import com.google.gson.Gson
+import okhttp3.MediaType.Companion.toMediaTypeOrNull
+import okhttp3.MultipartBody
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import okhttp3.RequestBody.Companion.asRequestBody
 import retrofit2.Call
 import retrofit2.Callback
 import retrofit2.Response
 import retrofit2.Retrofit
 import retrofit2.converter.gson.GsonConverterFactory
+import java.io.File
+import java.net.URLConnection
+
 
 interface LoginResultCallback {
     fun onSuccess(loginResponse: LoginResponse)
     fun onFailure(errorMessage: String)
 }
 
+interface UploadResultCallback {
+    fun onSuccess(uploadResponse: ItemsRoot)
+    fun onFailure(errorMessage: String)
+}
+
 interface CheckAuthResultCallback {
     fun onFailure()
 }
@@ -44,8 +57,15 @@ class CallBack<T> : Callback<T> {
 
 class Retrofit {
 
+    private val logger = HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY }
+
+    private val client = OkHttpClient.Builder()
+        .addInterceptor(logger)
+        .build()
+
     private val retrofit = Retrofit.Builder()
         .baseUrl("https://pbd-backend-2024.vercel.app/")
+        .client(client)
         .addConverterFactory(GsonConverterFactory.create())
         .build()
 
@@ -70,6 +90,53 @@ class Retrofit {
         })
     }
 
+    fun upload(context: Context, file: File, callback: UploadResultCallback) {
+        val scannerService = retrofit.create(ScannerService::class.java)
+        val sharedPreferences = context.getSharedPreferences(context.getString(R.string.preference_file_key), Context.MODE_PRIVATE)
+        val authHeader = "Bearer " + sharedPreferences.getString("login_token", "")
+
+        // Determine the MIME type of the file
+        val mimeType = URLConnection.guessContentTypeFromName(file.name)
+        if (mimeType == null) {
+            Log.e("ABE-PHO", "Could not determine MIME type of file")
+            return
+        }
+
+        // create RequestBody instance from file
+        val requestFile = file
+            .asRequestBody(mimeType.toMediaTypeOrNull())
+
+
+        // MultipartBody.Part is used to send also the actual file name
+        val body = MultipartBody.Part.createFormData("file", file.name, requestFile)
+
+        val call: Call<ItemsRoot> = scannerService.uploadScan(authHeader, body)
+
+        call.enqueue(object: Callback<ItemsRoot> {
+            override fun onResponse(call: Call<ItemsRoot>, response: Response<ItemsRoot>) {
+//                Log.d("ABE-PHO", "response: " + Gson().toJson(response.body()))
+//                Log.d("ABE-PHO", "error: " + Gson().toJson(response.errorBody()))
+//                Log.d("ABE-PHO", "code: " + response.code())
+//                Log.d("ABE-PHO", "headers: " + response.headers())
+//                Log.d("ABE-PHO", "message: " + response.message())
+
+                if (response.isSuccessful) {
+                    response.body()?.let {
+                        callback.onSuccess(it)
+                    }
+                } else {
+                    callback.onFailure("Upload failed")
+                }
+            }
+
+            override fun onFailure(call: Call<ItemsRoot>, t: Throwable) {
+                Log.d("ABE-PHO", "Failed to send request: " + t.message)
+                callback.onFailure("Failed to send photo")
+            }
+        })
+    }
+
+
     fun checkAuth(token: String, callback: CheckAuthResultCallback) {
         val checkAuthService = retrofit.create(CheckAuthService::class.java)
         val call: Call<CheckAuthResponse> = checkAuthService.checkAuth("Bearer $token")
diff --git a/app/src/main/java/com/example/abe/data/network/Services.kt b/app/src/main/java/com/example/abe/data/network/Services.kt
index 0b8ac796833aa606c6fa271c56a06e51524dce81..42eff784a360a550e29b48501ff71afdd8d988ba 100644
--- a/app/src/main/java/com/example/abe/data/network/Services.kt
+++ b/app/src/main/java/com/example/abe/data/network/Services.kt
@@ -1,17 +1,27 @@
 package com.example.abe.data.network
 
-import com.example.abe.data.network.LoginRequest
-import com.example.abe.data.network.LoginResponse
+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 LoginService {
     @POST("api/auth/login")
     fun login(@Body user: LoginRequest) : Call<LoginResponse>
 }
 
+interface ScannerService {
+    @Multipart
+    @POST("api/bill/upload")
+    fun uploadScan(
+        @Header("Authorization") authHeader: String,
+        @Part file: MultipartBody.Part
+    ): Call<ItemsRoot>
+}
+
 interface CheckAuthService {
     @POST("api/auth/token")
     fun checkAuth(@Header("Authorization") token: String) : Call<CheckAuthResponse>
diff --git a/app/src/main/java/com/example/abe/data/network/Types.kt b/app/src/main/java/com/example/abe/data/network/Types.kt
index 2e73e38be5dbde69407dd20a52082a14ade0fedd..e423b33a53a42e4b94da8eb9e738d55f86da2f47 100644
--- a/app/src/main/java/com/example/abe/data/network/Types.kt
+++ b/app/src/main/java/com/example/abe/data/network/Types.kt
@@ -9,8 +9,22 @@ data class LoginResponse (
     val token: String
 )
 
+data class TransactionItem(
+    val name: String,
+    val qty: Int,
+    val price: Double
+)
+
+data class ItemsContainer(
+    val items: List<TransactionItem>
+)
+
+data class ItemsRoot(
+    val items: ItemsContainer
+)
+
 data class CheckAuthResponse (
     val nim: String,
     val iat: String,
     val exp: String
-)
\ No newline at end of file
+)
diff --git a/app/src/main/java/com/example/abe/ui/notifications/NotificationsFragment.kt b/app/src/main/java/com/example/abe/ui/notifications/NotificationsFragment.kt
deleted file mode 100644
index d41dfc9b49a995133671578d2d2d103fdc22b18d..0000000000000000000000000000000000000000
--- a/app/src/main/java/com/example/abe/ui/notifications/NotificationsFragment.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.example.abe.ui.notifications
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.TextView
-import androidx.fragment.app.Fragment
-import androidx.lifecycle.ViewModelProvider
-import com.example.abe.databinding.FragmentNotificationsBinding
-
-class NotificationsFragment : Fragment() {
-
-    private var _binding: FragmentNotificationsBinding? = null
-
-    // This property is only valid between onCreateView and
-    // onDestroyView.
-    private val binding get() = _binding!!
-
-    override fun onCreateView(
-            inflater: LayoutInflater,
-            container: ViewGroup?,
-            savedInstanceState: Bundle?
-    ): View {
-        val notificationsViewModel =
-                ViewModelProvider(this).get(NotificationsViewModel::class.java)
-
-        _binding = FragmentNotificationsBinding.inflate(inflater, container, false)
-        val root: View = binding.root
-
-        val textView: TextView = binding.textNotifications
-        notificationsViewModel.text.observe(viewLifecycleOwner) {
-            textView.text = it
-        }
-        return root
-    }
-
-    override fun onDestroyView() {
-        super.onDestroyView()
-        _binding = null
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/abe/ui/scanner/ScannerFragment.kt b/app/src/main/java/com/example/abe/ui/scanner/ScannerFragment.kt
new file mode 100644
index 0000000000000000000000000000000000000000..164acc5667023182b516ed7a3bdbd417670e7a06
--- /dev/null
+++ b/app/src/main/java/com/example/abe/ui/scanner/ScannerFragment.kt
@@ -0,0 +1,373 @@
+package com.example.abe.ui.scanner
+
+import android.Manifest
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.app.Dialog
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import android.location.Address
+import android.location.Geocoder
+import android.location.LocationManager
+import android.net.Uri
+import android.os.Bundle
+import android.os.Environment
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.ImageView
+import android.widget.Toast
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.ImageCaptureException
+import androidx.camera.core.Preview
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.camera.view.PreviewView
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
+import androidx.navigation.fragment.findNavController
+import com.bumptech.glide.Glide
+import com.example.abe.ABEApplication
+import com.example.abe.R
+import com.example.abe.data.network.ItemsRoot
+import com.example.abe.data.network.Retrofit
+import com.example.abe.data.network.UploadResultCallback
+import com.example.abe.databinding.FragmentScanBinding
+import com.google.android.gms.location.FusedLocationProviderClient
+import com.google.android.gms.location.LocationServices
+import java.io.File
+import java.text.SimpleDateFormat
+import java.util.Locale
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+class ScannerFragment : Fragment(), UploadResultCallback {
+    private var _binding: FragmentScanBinding? = null
+    private val binding get() = _binding!!
+
+    private lateinit var cameraExecutor: ExecutorService
+    private lateinit var cameraView: PreviewView
+    private lateinit var imageCapture: ImageCapture
+    private lateinit var fusedLocationClient: FusedLocationProviderClient
+    private var latitude = 0.0
+    private var longitude = 0.0
+    private var useDefaultLocation = false
+
+    private val DEFAULT_LATITUDE = -6.892382
+    private val DEFAULT_LONGINTUDE = 107.608352
+
+    private lateinit var user: String
+
+    private val viewModel: ScannerViewModel by viewModels {
+        ScannerViewModelFactory((activity?.application as ABEApplication).repository)
+    }
+
+    private var isRequestingPermission = false
+
+    private var uploadResponse: ItemsRoot? = null
+
+    private val requestCameraPermissionLauncher =
+        registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
+            isRequestingPermission = false
+            if (isGranted) {
+                startCamera()
+            } else {
+                Toast.makeText(
+                    requireContext(),
+                    "Please allow access to camera to use scanner",
+                    Toast.LENGTH_LONG
+                ).show()
+            }
+        }
+
+    private fun uriToFile(imageUri: Uri): File {
+        val context = requireContext()
+        val inputStream = context.contentResolver.openInputStream(imageUri)
+        val tempFile = File.createTempFile("upload", ".jpg", context.cacheDir).apply {
+            outputStream().use { fileOut ->
+                inputStream?.copyTo(fileOut)
+            }
+        }
+        inputStream?.close()
+        return tempFile
+    }
+
+    private val openGalleryLauncher =
+        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
+            if (result.resultCode == Activity.RESULT_OK) {
+                val imageUri = result.data?.data
+                if (imageUri != null) {
+                    val imageFile = uriToFile(imageUri)
+                    attemptUpload(imageFile)
+
+                    val msg = "Uploading photo, please wait"
+                    Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show()
+                } else {
+                    val msg = "Failed to fetch image from gallery"
+                    Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show()
+                }
+            }
+        }
+
+    override fun onCreateView(
+        inflater: LayoutInflater, container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View {
+        _binding = FragmentScanBinding.inflate(inflater, container, false)
+        cameraView = binding.camera
+        cameraExecutor = Executors.newSingleThreadExecutor()
+
+        if (!cameraPermissionGranted()) {
+            requestCameraPermission()
+        } else {
+            startCamera()
+        }
+
+        val sharedPref = activity?.getSharedPreferences(
+            getString(R.string.preference_file_key),
+            Context.MODE_PRIVATE
+        )
+        user = sharedPref?.getString("user", "").toString()
+
+        binding.captureButton.setOnClickListener {
+            takePicture()
+        }
+
+        binding.galleryPreviewButton.setOnClickListener {
+            openGallery()
+        }
+
+        return binding.root
+    }
+
+    companion object {
+        private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
+    }
+
+    private fun startCamera() {
+        val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
+
+        cameraProviderFuture.addListener({
+            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
+
+            val preview = Preview.Builder()
+                .build()
+                .also {
+                    it.setSurfaceProvider(cameraView.surfaceProvider)
+                }
+
+            imageCapture = ImageCapture.Builder()
+                .build()
+
+            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
+
+            try {
+                cameraProvider.unbindAll()
+
+                cameraProvider.bindToLifecycle(
+                    viewLifecycleOwner, cameraSelector, preview, imageCapture
+                )
+
+            } catch (exc: Exception) {
+                exc.printStackTrace()
+            }
+
+        }, ContextCompat.getMainExecutor(requireContext()))
+    }
+
+    private fun attemptUpload(imageFile: File) {
+        val retrofit = Retrofit()
+        val context = requireContext()
+        retrofit.upload(context, imageFile, this)
+    }
+
+    private fun showPreviewDialog(imageUri: Uri) {
+        val dialog = Dialog(requireContext()).apply {
+            setContentView(R.layout.dialog_image_preview)
+            window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
+        }
+
+        val imageView = dialog.findViewById<ImageView>(R.id.dialog_image_view)
+
+        Glide.with(requireContext())
+            .load(imageUri)
+            .into(imageView)
+
+        val confirmButton = dialog.findViewById<Button>(R.id.confirm_button)
+        val cancelButton = dialog.findViewById<Button>(R.id.cancel_button)
+
+        confirmButton.setOnClickListener {
+            val filePath = imageUri.path
+            if (filePath != null) {
+                val imageFile = File(filePath)
+                attemptUpload(imageFile)
+
+                val msg = "Uploading photo, please wait"
+                Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show()
+
+                dialog.dismiss()
+            } else {
+                dialog.dismiss()
+            }
+        }
+
+        cancelButton.setOnClickListener {
+            dialog.dismiss()
+        }
+
+        dialog.show()
+    }
+
+    private fun takePicture() {
+        val imageCapture = imageCapture
+
+        val photoFile = File(
+            requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES),
+            SimpleDateFormat(FILENAME_FORMAT, Locale.US).format(System.currentTimeMillis()) + ".jpg"
+        )
+
+        val outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()
+
+        imageCapture.takePicture(
+            outputOptions,
+            ContextCompat.getMainExecutor(requireContext()),
+            object : ImageCapture.OnImageSavedCallback {
+                override fun onError(exc: ImageCaptureException) {
+                    Toast.makeText(requireContext(), "Photo capture failed", Toast.LENGTH_SHORT)
+                        .show()
+                }
+
+                override fun onImageSaved(output: ImageCapture.OutputFileResults) {
+                    val savedUri = Uri.fromFile(photoFile)
+                    showPreviewDialog(savedUri)
+                }
+            }
+        )
+    }
+
+    private fun setLocationAsDefault() {
+        latitude = DEFAULT_LATITUDE
+        longitude = DEFAULT_LONGINTUDE
+        useDefaultLocation = true
+    }
+
+    @SuppressLint("MissingPermission")
+    private fun getCurrentLocationAndInsertTrx() {
+        fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireActivity())
+
+        if (checkLocationPermissions() && checkIfLocationEnabled()) {
+            fusedLocationClient.lastLocation
+                .addOnCompleteListener(requireActivity()) { task ->
+                    val location = task.result
+                    if (location != null) {
+                        latitude = location.latitude
+                        longitude = location.longitude
+                    } else {
+                        setLocationAsDefault()
+                    }
+                    insertItems()
+                }
+        } else {
+            setLocationAsDefault()
+        }
+    }
+
+    private fun checkLocationPermissions(): Boolean {
+        return ActivityCompat.checkSelfPermission(
+            requireActivity(), Manifest.permission.ACCESS_COARSE_LOCATION
+        ) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
+            requireActivity(), Manifest.permission.ACCESS_FINE_LOCATION
+        ) == PackageManager.PERMISSION_GRANTED
+    }
+
+    private fun checkIfLocationEnabled(): Boolean {
+        val locationManager: LocationManager =
+            requireActivity().getSystemService(Context.LOCATION_SERVICE) as LocationManager
+        return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(
+            LocationManager.NETWORK_PROVIDER
+        )
+    }
+
+    private fun askForLocationPermissions() {
+        requestLocationLauncher.launch(
+            arrayOf(
+                Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION
+            )
+        )
+    }
+
+    private val requestLocationLauncher =
+        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
+            var granted = false
+            permissions.entries.forEach {
+                if (it.value) granted = true
+            }
+            if (granted) {
+                getCurrentLocationAndInsertTrx()
+            } else {
+                setLocationAsDefault()
+                insertItems()
+            }
+        }
+
+    override fun onSuccess(uploadResponse: ItemsRoot) {
+        this.uploadResponse = uploadResponse
+
+        if (checkLocationPermissions()) {
+            getCurrentLocationAndInsertTrx()
+        } else {
+            askForLocationPermissions()
+        }
+    }
+
+    fun insertItems() {
+        val geocoder = Geocoder(requireContext(), Locale.getDefault())
+        val locationList: MutableList<Address> =
+            geocoder.getFromLocation(latitude, longitude, 1) ?: mutableListOf<Address>()
+        val location =
+            if (!useDefaultLocation && locationList.size > 0) (locationList[0].getAddressLine(0)) else "Unknown location"
+
+        uploadResponse?.items?.items?.forEach { item ->
+            viewModel.insertTransaction(user, item, latitude, longitude, location)
+        }
+        val msg = "New transactions added!"
+        Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show()
+
+        findNavController().navigate(R.id.action_navigation_scanner_to_navigation_transactions)
+        uploadResponse = null
+    }
+
+    override fun onFailure(errorMessage: String) {
+        Toast.makeText(requireContext(), "Upload failed", Toast.LENGTH_SHORT).show()
+        Log.e("ABE-PHO", errorMessage)
+    }
+
+    private fun openGallery() {
+        val intent = Intent(Intent.ACTION_PICK)
+        intent.type = "image/*"
+        openGalleryLauncher.launch(intent)
+    }
+
+    private fun cameraPermissionGranted() = ContextCompat.checkSelfPermission(
+        requireContext(), Manifest.permission.CAMERA
+    ) == PackageManager.PERMISSION_GRANTED
+
+    private fun requestCameraPermission() {
+        isRequestingPermission = true
+        requestCameraPermissionLauncher.launch(Manifest.permission.CAMERA)
+    }
+
+    override fun onDestroyView() {
+        super.onDestroyView()
+        cameraExecutor.shutdown()
+        _binding = null
+    }
+}
diff --git a/app/src/main/java/com/example/abe/ui/scanner/ScannerViewModel.kt b/app/src/main/java/com/example/abe/ui/scanner/ScannerViewModel.kt
new file mode 100644
index 0000000000000000000000000000000000000000..5cfd8170db1d62a93d9160da905d379aa34d244a
--- /dev/null
+++ b/app/src/main/java/com/example/abe/ui/scanner/ScannerViewModel.kt
@@ -0,0 +1,41 @@
+package com.example.abe.ui.scanner
+
+import androidx.lifecycle.ViewModel
+import com.example.abe.data.TransactionRepository
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.Dispatchers
+import com.example.abe.data.Transaction
+import com.example.abe.data.network.TransactionItem
+import java.util.Date
+
+class ScannerViewModel(private val transactionRepository: TransactionRepository):
+    ViewModel() {
+    fun insertTransaction(user: String, item: TransactionItem, lat: Double, long: Double, location: String) = viewModelScope.launch(Dispatchers.IO) {
+        val transaction = Transaction(
+            id = 0,
+            email = user,
+            title = item.name,
+            amount = (item.qty * item.price).toInt(),
+            isExpense = (item.qty * item.price).toInt() < 0,
+            timestamp = Date(),
+            latitude = lat,
+            longitude = long,
+            location = location,
+        )
+        transactionRepository.insert(transaction)
+    }
+}
+
+
+class ScannerViewModelFactory(private val repository: TransactionRepository) :
+    ViewModelProvider.Factory {
+    override fun <T : ViewModel> create(modelClass: Class<T>): T {
+        if (modelClass.isAssignableFrom(ScannerViewModel::class.java)) {
+            @Suppress("UNCHECKED_CAST")
+            return ScannerViewModel(repository) as T
+        }
+        throw IllegalArgumentException("Unknown viewmodel class")
+    }
+}
diff --git a/app/src/main/java/com/example/abe/ui/notifications/NotificationsViewModel.kt b/app/src/main/java/com/example/abe/ui/settings/SettingsViewModel.kt
similarity index 75%
rename from app/src/main/java/com/example/abe/ui/notifications/NotificationsViewModel.kt
rename to app/src/main/java/com/example/abe/ui/settings/SettingsViewModel.kt
index 56b1bbe6ff5e1f05774b1c318c49465fe6ae5574..e0de351d8ea4503d22739cc25d035ff851b6f7a1 100644
--- a/app/src/main/java/com/example/abe/ui/notifications/NotificationsViewModel.kt
+++ b/app/src/main/java/com/example/abe/ui/settings/SettingsViewModel.kt
@@ -1,10 +1,10 @@
-package com.example.abe.ui.notifications
+package com.example.abe.ui.settings
 
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.ViewModel
 
-class NotificationsViewModel : ViewModel() {
+class SettingsViewModel : ViewModel() {
 
     private val _text = MutableLiveData<String>().apply {
         value = "This is notifications Fragment"
diff --git a/app/src/main/java/com/example/abe/ui/transactions/TransactionsAdapter.kt b/app/src/main/java/com/example/abe/ui/transactions/TransactionsAdapter.kt
index 96eeae3a9bc2f6ab3a8979ed7afed44e43c50f06..da0124b12db5ec09ad008dd4b908c56a8136bd0a 100644
--- a/app/src/main/java/com/example/abe/ui/transactions/TransactionsAdapter.kt
+++ b/app/src/main/java/com/example/abe/ui/transactions/TransactionsAdapter.kt
@@ -60,6 +60,10 @@ class TransactionsAdapter(private val itemClickListener: TransactionFragment.Ite
                 flImageContainer.setBackgroundColor(context.getColor(R.color.secondary))
                 ivTrxIcon.setImageResource(R.drawable.ic_circle_arrow_down)
                 tvAmount.setTextColor(context.getColor(R.color.success))
+            } else {
+                flImageContainer.setBackgroundColor(context.getColor(R.color.primary))
+                ivTrxIcon.setImageResource(R.drawable.ic_circle_arrow_up)
+                tvAmount.setTextColor(context.getColor(R.color.destructive))
             }
 
             tvTrxTitle.text = trx.title
diff --git a/app/src/main/res/drawable-anydpi/ic_gallery.xml b/app/src/main/res/drawable-anydpi/ic_gallery.xml
new file mode 100644
index 0000000000000000000000000000000000000000..054d3d09d1ff1a78a3c50c1e68db22d6d89d99b2
--- /dev/null
+++ b/app/src/main/res/drawable-anydpi/ic_gallery.xml
@@ -0,0 +1,14 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="#FFFFFF"
+    android:alpha="0.8">
+  <group android:scaleX="1.0434783"
+      android:scaleY="1.0434783">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M3,4V1h2v3h3v2H5v3H3V6H0V4H3zM6,10V7h3V4h7l1.83,2H21c1.1,0 2,0.9 2,2v12c0,1.1 -0.9,2 -2,2H5c-1.1,0 -2,-0.9 -2,-2V10H6zM13,19c2.76,0 5,-2.24 5,-5s-2.24,-5 -5,-5s-5,2.24 -5,5S10.24,19 13,19zM9.8,14c0,1.77 1.43,3.2 3.2,3.2s3.2,-1.43 3.2,-3.2s-1.43,-3.2 -3.2,-3.2S9.8,12.23 9.8,14z"/>
+  </group>
+</vector>
diff --git a/app/src/main/res/drawable-hdpi/ic_gallery.png b/app/src/main/res/drawable-hdpi/ic_gallery.png
new file mode 100644
index 0000000000000000000000000000000000000000..199c0ce52e5a1598f24082e371615275ba2d8d02
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_gallery.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_logout.png b/app/src/main/res/drawable-hdpi/ic_logout.png
new file mode 100644
index 0000000000000000000000000000000000000000..9331e62770bdc4c74fbcedcd7ac57a67c502fcfb
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_logout.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_randomize.png b/app/src/main/res/drawable-hdpi/ic_randomize.png
new file mode 100644
index 0000000000000000000000000000000000000000..667f0c88fcdf83348117bd3a479618e7f5533689
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_randomize.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_gallery.png b/app/src/main/res/drawable-mdpi/ic_gallery.png
new file mode 100644
index 0000000000000000000000000000000000000000..ba50d7049809d681e0774ccf7e948e73939023f3
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_gallery.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_logout.png b/app/src/main/res/drawable-mdpi/ic_logout.png
new file mode 100644
index 0000000000000000000000000000000000000000..d55f5e0a6c9ede1869e96fc291687bb47f3dd642
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_logout.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_randomize.png b/app/src/main/res/drawable-mdpi/ic_randomize.png
new file mode 100644
index 0000000000000000000000000000000000000000..28fe11ceadb9ba92f3f46a527c9036f251a7f9cf
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_randomize.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_gallery.png b/app/src/main/res/drawable-xhdpi/ic_gallery.png
new file mode 100644
index 0000000000000000000000000000000000000000..b150affe38e4704e55c6fb478f4721a0ff085eb3
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_gallery.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_logout.png b/app/src/main/res/drawable-xhdpi/ic_logout.png
new file mode 100644
index 0000000000000000000000000000000000000000..0a31e5c76a1adb317743c9cfc29a2efb8d8eaa81
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_logout.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_randomize.png b/app/src/main/res/drawable-xhdpi/ic_randomize.png
new file mode 100644
index 0000000000000000000000000000000000000000..69556c93f3150ba6ecd99046b83d74ae3e625400
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_randomize.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_gallery.png b/app/src/main/res/drawable-xxhdpi/ic_gallery.png
new file mode 100644
index 0000000000000000000000000000000000000000..3ee421e0604f237e0db30b9f934b7920a91c1d5d
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_gallery.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_logout.png b/app/src/main/res/drawable-xxhdpi/ic_logout.png
new file mode 100644
index 0000000000000000000000000000000000000000..55ffdf3d403032f16eec496e96c7eeec41668f6a
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_logout.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_randomize.png b/app/src/main/res/drawable-xxhdpi/ic_randomize.png
new file mode 100644
index 0000000000000000000000000000000000000000..a02988c35002ee927718e550687c6ef2665f665f
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_randomize.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_logout.png b/app/src/main/res/drawable-xxxhdpi/ic_logout.png
new file mode 100644
index 0000000000000000000000000000000000000000..52878a94028e2718d194435ed96be10c7ffb023f
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_logout.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_randomize.png b/app/src/main/res/drawable-xxxhdpi/ic_randomize.png
new file mode 100644
index 0000000000000000000000000000000000000000..c901103051b2216baa691432683db052d66bd96d
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_randomize.png differ
diff --git a/app/src/main/res/drawable/bottom_bar_scan.xml b/app/src/main/res/drawable/bottom_bar_scan.xml
new file mode 100644
index 0000000000000000000000000000000000000000..00381290052c3ecaea4e18b83de11c40b8e0c44b
--- /dev/null
+++ b/app/src/main/res/drawable/bottom_bar_scan.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#8346AA"/>
+    <corners android:topLeftRadius="16dp" android:topRightRadius="16dp"/>
+</shape>
diff --git a/app/src/main/res/drawable/scan_button.xml b/app/src/main/res/drawable/scan_button.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a5fb15718943d7a69357567e61ee2001f7e5929e
--- /dev/null
+++ b/app/src/main/res/drawable/scan_button.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:top="2dp" android:bottom="2dp" android:left="2dp" android:right="2dp">
+        <shape android:shape="oval">
+            <solid android:color="@color/white"/>
+            <size android:width="68dp" android:height="68dp"/>
+        </shape>
+    </item>
+</layer-list>
diff --git a/app/src/main/res/layout/dialog_image_preview.xml b/app/src/main/res/layout/dialog_image_preview.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d20c44d11ff527c054858c99aad61fc1407708bd
--- /dev/null
+++ b/app/src/main/res/layout/dialog_image_preview.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+
+    <ImageView
+        android:id="@+id/dialog_image_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        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.5"
+        tools:srcCompat="@tools:sample/avatars" />
+
+    <Button
+        android:id="@+id/confirm_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="48dp"
+        android:text="Confirm"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toStartOf="@id/cancel_button"
+        app:layout_constraintHorizontal_chainStyle="spread"
+        app:layout_constraintStart_toStartOf="parent" />
+
+    <Button
+        android:id="@+id/cancel_button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="Cancel"
+        app:layout_constraintBottom_toBottomOf="@+id/confirm_button"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toEndOf="@id/confirm_button"
+        app:layout_constraintTop_toTopOf="@+id/confirm_button" />
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_notifications.xml b/app/src/main/res/layout/fragment_notifications.xml
deleted file mode 100644
index d41793572bb3b8347ec4bced74b7bd4a43bed5d4..0000000000000000000000000000000000000000
--- a/app/src/main/res/layout/fragment_notifications.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    tools:context=".ui.notifications.NotificationsFragment">
-
-    <TextView
-        android:id="@+id/text_notifications"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="8dp"
-        android:layout_marginTop="8dp"
-        android:layout_marginEnd="8dp"
-        android:textAlignment="center"
-        android:textSize="20sp"
-        app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="parent"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent" />
-</androidx.constraintlayout.widget.ConstraintLayout>
\ 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..f3b6fe9600caee95ac502101998fdb111b87a32d
--- /dev/null
+++ b/app/src/main/res/layout/fragment_scan.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/scan_screen"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <androidx.camera.view.PreviewView
+        android:id="@+id/camera"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        app:layout_constraintBottom_toTopOf="@+id/bottom_bar"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintHorizontal_bias="0.5"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_bias="0.5"
+        app:layout_constraintVertical_chainStyle="packed">
+
+    </androidx.camera.view.PreviewView>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/bottom_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@drawable/bottom_bar_scan"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent">
+
+        <Button
+            android:id="@+id/captureButton"
+            android:layout_width="80dp"
+            android:layout_height="80dp"
+            android:layout_marginTop="16dp"
+            android:layout_marginBottom="16dp"
+            android:background="@drawable/scan_button"
+            android:backgroundTint="#FFFFFF"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <ImageButton
+            android:id="@+id/galleryPreviewButton"
+            android:layout_width="52dp"
+            android:layout_height="52dp"
+            android:adjustViewBounds="true"
+            android:background="?attr/selectableItemBackgroundBorderless"
+            android:contentDescription="Get Photo from Gallery"
+            android:padding="10dp"
+            android:scaleType="fitCenter"
+            android:src="@drawable/ic_gallery"
+            app:layout_constraintBottom_toBottomOf="@+id/captureButton"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toEndOf="@+id/captureButton"
+            app:layout_constraintTop_toTopOf="@+id/captureButton" />
+
+
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml
index cd5cb7f7c224557b131277efbce9121f5c666bb1..58927cd8ee50852868f44146fbb513194849ba1b 100644
--- a/app/src/main/res/menu/bottom_nav_menu.xml
+++ b/app/src/main/res/menu/bottom_nav_menu.xml
@@ -6,10 +6,10 @@
         android:icon="@drawable/ic_transactions"
         android:title="Transaction" />
 
-<!--    <item-->
-<!--        android:id="@+id/navigation_scan"-->
-<!--        android:icon="@drawable/ic_scan"-->
-<!--        android:title="Scan" />-->
+    <item
+        android:id="@+id/navigation_scan"
+        android:icon="@drawable/ic_scan"
+        android:title="Scan" />
 
     <item
         android:id="@+id/navigation_graph"
diff --git a/app/src/main/res/mipmap-hdpi/ic_add_image.png b/app/src/main/res/mipmap-hdpi/ic_add_image.png
new file mode 100644
index 0000000000000000000000000000000000000000..e19abb5f6e9e58db13a2be2911c1af6f1c9900da
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_add_image.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_add_image.png b/app/src/main/res/mipmap-mdpi/ic_add_image.png
new file mode 100644
index 0000000000000000000000000000000000000000..697de1a29c461476970a0f0fc8816e87b93300fa
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_add_image.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_add_image.png b/app/src/main/res/mipmap-xhdpi/ic_add_image.png
new file mode 100644
index 0000000000000000000000000000000000000000..a848fd35eb0e6da98b11936e14b642320e93a1b7
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_add_image.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_add_image.png b/app/src/main/res/mipmap-xxhdpi/ic_add_image.png
new file mode 100644
index 0000000000000000000000000000000000000000..964d86c27a91b5c1944bb7be62c4348092b4ba75
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_add_image.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_add_image.png b/app/src/main/res/mipmap-xxxhdpi/ic_add_image.png
new file mode 100644
index 0000000000000000000000000000000000000000..cbcc9c81cb77e8fb8a77de5a71b8ea0512b1064f
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_add_image.png differ
diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml
index 6b817e8f061acda53c67e1547f0709d95b6e4fce..db6d987e9ce1229fcf6758fbb7477e47c86d59bd 100644
--- a/app/src/main/res/navigation/mobile_navigation.xml
+++ b/app/src/main/res/navigation/mobile_navigation.xml
@@ -26,11 +26,19 @@
         tools:layout="@layout/fragment_form_transaction"
         />
 
-<!--    <fragment-->
-<!--        android:id="@+id/navigation_scan"-->
-<!--        android:name="com.example.abe.ui.scanner.ScannerFragment"-->
-<!--        android:label="Scan"-->
-<!--        tools:layout="@layout/fragment_scan" />-->
+    <fragment
+        android:id="@+id/navigation_scan"
+        android:name="com.example.abe.ui.scanner.ScannerFragment"
+        android:label="Scan"
+        tools:layout="@layout/fragment_scan">
+
+        <action
+            android:id="@+id/action_navigation_scanner_to_navigation_transactions"
+            app:destination="@+id/navigation_transactions"
+            app:popUpTo="@id/navigation_transactions"
+            app:popUpToInclusive="true"
+            />
+    </fragment>
 
     <fragment
         android:id="@+id/navigation_graph"
@@ -39,10 +47,6 @@
         tools:layout="@layout/fragment_graph"
         />
 
-<!--    <fragment-->
-<!--        android:id="@+id/navigation_graph"-->
-<!--        android:label="Graph" />-->
-
     <fragment
         android:id="@+id/navigation_settings"
         android:name="com.example.abe.ui.settings.SettingsFragment"
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 0016c8555aad7b0adf46b96f07a24acfc83d5bb0..e5e09b1293522859c5ffd5fe710e064d1f791d1a 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -25,6 +25,8 @@ poiOoxml = "5.2.5"
 activity = "1.8.0"
 playServicesLocation = "21.2.0"
 camerax = "1.4.0-alpha04"
+glide = "4.12.0"
+okhttp = "4.9.0"
 
 [libraries]
 androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -53,6 +55,10 @@ play-services-location = { group = "com.google.android.gms", name = "play-servic
 camera-core = { module = "androidx.camera:camera-camera2", version.ref = "camerax" }
 camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "camerax" }
 camera-view = { module = "androidx.camera:camera-view", version.ref = "camerax" }
+glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" }
+glideCompiler = { module = "com.github.bumptech.glide:compiler", version.ref = "glide" }
+okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
+logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" }
 
 [plugins]
 androidApplication = { id = "com.android.application", version.ref = "agp" }