diff --git a/app/src/main/java/com/example/bondoman/ui/upload/UploadFragment.kt b/app/src/main/java/com/example/bondoman/ui/upload/UploadFragment.kt
index 746df5970ce60c69bd9081d9a6511213ef416fbd..274274e3b77accf6924f1ff8be6f3c06d34cafc5 100644
--- a/app/src/main/java/com/example/bondoman/ui/upload/UploadFragment.kt
+++ b/app/src/main/java/com/example/bondoman/ui/upload/UploadFragment.kt
@@ -1,15 +1,15 @@
 package com.example.bondoman.ui.upload
 
 import android.Manifest
-import android.content.ContentValues
 import android.content.pm.PackageManager
+import android.os.Build
 import android.os.Bundle
-import android.provider.MediaStore
 import android.util.Log
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
 import android.widget.Toast
+import androidx.activity.result.PickVisualMediaRequest
 import androidx.activity.result.contract.ActivityResultContracts
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.ImageCapture
@@ -27,11 +27,10 @@ import com.example.bondoman.share_preference.PreferenceManager
 import okhttp3.MediaType.Companion.toMediaType
 import okhttp3.MultipartBody
 import java.io.File
-import java.text.SimpleDateFormat
-import java.util.Locale
 import java.util.concurrent.ExecutorService
 import java.util.concurrent.Executors
 import okhttp3.RequestBody.Companion.asRequestBody
+import java.io.FileOutputStream
 
 class UploadFragment : Fragment() {
 
@@ -70,6 +69,39 @@ class UploadFragment : Fragment() {
         }
     }
 
+    private val pickMedia = registerForActivityResult(
+        ActivityResultContracts.PickVisualMedia()
+    ) { uri ->
+        if (uri != null) {
+            Log.d("Upload Fragment", "Selected uri: $uri")
+
+            val inputStream = requireContext().contentResolver.openInputStream(uri)
+
+            file = File.createTempFile("TEMP_FILE_", ".jpg", requireContext().cacheDir)
+            val outputStream = FileOutputStream(file)
+
+            inputStream!!.use { input ->
+                outputStream.use { output ->
+                    input.copyTo(output)
+                }
+            }
+
+            val mediaType = "image/jpeg"
+
+            val part = MultipartBody.Part.createFormData(
+                "file",
+                file.name,
+                file.asRequestBody(mediaType.toMediaType())
+            )
+
+            val token = preferenceManager.getToken()
+
+            viewModel.upload(token, part)
+        } else {
+            Log.d("Upload Fragment", "No media selected")
+        }
+    }
+
     private fun goToUploadResultFragment() {
         val items: Array<Item> = viewModel.items.value!!.items.toTypedArray()
         val parcelableItem: Array<ParcelableItem> = items.map {
@@ -89,7 +121,12 @@ class UploadFragment : Fragment() {
             requestPermissions()
         }
 
-        // Set up the listeners to take photo and video capture buttons
+        // Set up the listeners to pick image
+        binding.scanImagePickerButton.setOnClickListener {
+            pickMedia.launch(PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly))
+        }
+
+        // Set up the listeners to take photo
         binding.imageCaptureButton.setOnClickListener {
             takePhoto()
 
@@ -115,6 +152,16 @@ class UploadFragment : Fragment() {
 
         viewModel.errorMessage.observe(viewLifecycleOwner) { res ->
             Log.d("Upload Fragment", res.toString())
+
+            if (res.toString() == "Unauthorized") {
+                Toast.makeText(
+                    requireContext(), "Token has expired, please log in again", Toast.LENGTH_LONG
+                ).show()
+            } else {
+                Toast.makeText(
+                    requireContext(), "Server unreachable, please try again", Toast.LENGTH_LONG
+                ).show()
+            }
         }
 
         cameraExecutor = Executors.newSingleThreadExecutor()
@@ -124,13 +171,6 @@ class UploadFragment : Fragment() {
         // Get a stable reference of the modifiable image capture use cases
         val imageCapture = imageCapture ?: return
 
-        // Create time stamped name and MediaStory entry
-        val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US).format(System.currentTimeMillis())
-        val contentValues = ContentValues().apply {
-            put(MediaStore.MediaColumns.DISPLAY_NAME, name)
-            put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
-        }
-
         // Create output options object which contains file + metadata
         file = File.createTempFile("TEMP_FILE_", ".jpg", requireContext().cacheDir)
         val outputOptions = ImageCapture.OutputFileOptions.Builder(file).build()
@@ -140,16 +180,14 @@ class UploadFragment : Fragment() {
             ContextCompat.getMainExecutor(requireContext()),
             object : ImageCapture.OnImageSavedCallback {
                 override fun onError(exception: ImageCaptureException) {
-                    Log.e(TAG, "Photo capture failed: ${exception.message}", exception)
+                    Log.e(
+                        "Upload Fragment",
+                        "Photo capture failed: ${exception.message}",
+                        exception
+                    )
                 }
 
                 override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
-                    val msg = "Photo captured successfully: ${outputFileResults.savedUri}"
-
-                    // TODO: remove
-                    Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show()
-                    Log.d(TAG, msg)
-
                     Log.d("Upload Fragment", file.name)
                 }
             })
@@ -183,7 +221,7 @@ class UploadFragment : Fragment() {
                     this, cameraSelector, preview, imageCapture
                 )
             } catch (exception: Exception) {
-                Log.e(TAG, "Use case binding failed", exception)
+                Log.e("Upload Fragment", "Use case binding failed", exception)
             }
         }, ContextCompat.getMainExecutor(requireContext()))
     }
@@ -204,11 +242,17 @@ class UploadFragment : Fragment() {
     }
 
     companion object {
-        private const val TAG = "BONDOMAN"
-        private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
         private val REQUIRED_PERMISSIONS = mutableListOf(
             Manifest.permission.CAMERA
-        ).toTypedArray()
+        ).apply {
+            add(
+                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
+                    Manifest.permission.READ_EXTERNAL_STORAGE
+                } else {
+                    Manifest.permission.READ_MEDIA_IMAGES
+                }
+            )
+        }.toTypedArray()
     }
 
     override fun onCreateView(