diff --git a/app/src/main/java/com/example/bondoman/ui/twibbon/TwibbonFragment.kt b/app/src/main/java/com/example/bondoman/ui/twibbon/TwibbonFragment.kt index aff5734550c0b443e1e03c10e0f7edd8f13e2cfb..4d2e39e84bd1c78088f4405d0e168c0221fcb686 100644 --- a/app/src/main/java/com/example/bondoman/ui/twibbon/TwibbonFragment.kt +++ b/app/src/main/java/com/example/bondoman/ui/twibbon/TwibbonFragment.kt @@ -1,33 +1,77 @@ package com.example.bondoman.ui.twibbon +import android.Manifest +import android.app.Activity +import android.app.AlertDialog +import android.content.pm.PackageManager import android.os.Bundle import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.camera.core.ImageCapture +import androidx.core.content.ContextCompat import com.example.bondoman.R +import com.example.bondoman.databinding.FragmentScanBinding +import java.util.concurrent.ExecutorService +import java.util.concurrent.Executors +import android.content.Context +import android.content.Intent +import android.graphics.BitmapFactory +import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts +import androidx.camera.lifecycle.ProcessCameraProvider +import androidx.camera.core.Preview +import androidx.camera.core.CameraSelector +import android.util.Log +import android.widget.ImageView +import androidx.camera.core.ImageCaptureException +import androidx.camera.core.ImageProxy +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.example.bondoman.databinding.FragmentTwibbonBinding +import com.example.bondoman.models.Item +import com.example.bondoman.services.RetrofitClient +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import okhttp3.MediaType +import okhttp3.MultipartBody +import okhttp3.RequestBody +import retrofit2.HttpException -// TODO: Rename parameter arguments, choose names that match -// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER -private const val ARG_PARAM1 = "param1" -private const val ARG_PARAM2 = "param2" -/** - * A simple [Fragment] subclass. - * Use the [TwibbonFragment.newInstance] factory method to - * create an instance of this fragment. - */ class TwibbonFragment : Fragment() { // TODO: Rename and change types of parameters - private var param1: String? = null - private var param2: String? = null + private lateinit var viewBinding: FragmentTwibbonBinding + + private var imageCapture : ImageCapture? = null + + private lateinit var cameraExecutor: ExecutorService + + private var previewFrozen: Boolean = false + + private val activityResultLauncher = + registerForActivityResult( + ActivityResultContracts.RequestMultiplePermissions()) + { permissions -> + var permissionGranted = true + permissions.entries.forEach { + if (it.key in REQUIRED_PERMISSIONS && !it.value) + permissionGranted = false + } + if (!permissionGranted) { + Toast.makeText(requireContext(), + "Permission request denied", + Toast.LENGTH_SHORT).show() + } else { + startCamera() + } + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - arguments?.let { - param1 = it.getString(ARG_PARAM1) - param2 = it.getString(ARG_PARAM2) - } } override fun onCreateView( @@ -38,23 +82,88 @@ class TwibbonFragment : Fragment() { return inflater.inflate(R.layout.fragment_twibbon, container, false) } - companion object { - /** - * Use this factory method to create a new instance of - * this fragment using the provided parameters. - * - * @param param1 Parameter 1. - * @param param2 Parameter 2. - * @return A new instance of fragment TwibbonFragment. - */ - // TODO: Rename and change types and number of parameters - @JvmStatic - fun newInstance(param1: String, param2: String) = - TwibbonFragment().apply { - arguments = Bundle().apply { - putString(ARG_PARAM1, param1) - putString(ARG_PARAM2, param2) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + viewBinding = FragmentTwibbonBinding.bind(view) + + if (allPermissionsGranted()){ + startCamera() + }else{ + requestPermissions() + } + + viewBinding.twibbonCaptureButton.setOnClickListener { takePhoto() } + + cameraExecutor = Executors.newSingleThreadExecutor() + } + + private fun startCamera() { + val cameraProviderFuture = ProcessCameraProvider.getInstance(requireActivity()) + + cameraProviderFuture.addListener({ + val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() + + val preview = Preview.Builder().build().also { + mPreview -> + if (!previewFrozen) { + mPreview.setSurfaceProvider(viewBinding.viewFinder.surfaceProvider) + } else { + mPreview.setSurfaceProvider(null) } } + + imageCapture = ImageCapture.Builder() + .build() + + val cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA + + try { + cameraProvider.unbindAll() + + cameraProvider.bindToLifecycle( + this, cameraSelector, preview, imageCapture) + + } catch(exc: Exception) { + Log.e(TAG, "Use case binding failed", exc) + } + + }, ContextCompat.getMainExecutor(requireActivity())) + } + + private fun requestPermissions(){ + activityResultLauncher.launch(REQUIRED_PERMISSIONS) + } + + private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all { + ContextCompat.checkSelfPermission( + requireContext(), it + ) == PackageManager.PERMISSION_GRANTED + } + + private fun takePhoto() { + + previewFrozen = !previewFrozen + if (!previewFrozen) { + viewBinding.twibbonCaptureButton.text = "Capture" + } else { + viewBinding.twibbonCaptureButton.text = "Retake" + } + startCamera() + } + + + override fun onDestroy() { + super.onDestroy() + cameraExecutor.shutdown() + } + + companion object { + private const val TAG = "BondoMan" + private val REQUIRED_PERMISSIONS = + mutableListOf( + Manifest.permission.CAMERA, + Manifest.permission.READ_EXTERNAL_STORAGE + ).toTypedArray() } } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_twibbon.xml b/app/src/main/res/layout/fragment_twibbon.xml index 2a891590177012eeb82766ecee1891a000a2d9ef..94ad224df90a1aa08d77013916b01f921b0f40f4 100644 --- a/app/src/main/res/layout/fragment_twibbon.xml +++ b/app/src/main/res/layout/fragment_twibbon.xml @@ -1,16 +1,65 @@ <?xml version="1.0" encoding="utf-8"?> -<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" +<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.twibbon.TwibbonFragment"> + tools:context=".MainActivity"> + + <FrameLayout + android:id="@+id/frameLayout" + android:layout_width="411dp" + android:layout_height="wrap_content" + android:visibility="visible" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.0"> + + <androidx.camera.view.PreviewView + android:id="@+id/viewFinder" + android:layout_width="match_parent" + android:layout_height="372dp" + android:layout_marginTop="43dp" /> + + <ImageView + android:id="@+id/imageView3" + android:layout_width="wrap_content" + android:layout_height="369dp" + android:src="@drawable/bondoman_logo" + android:translationY="42dp" /> + + </FrameLayout> + + <Button + android:id="@+id/twibbonCaptureButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="16dp" + android:fontFamily="sans-serif" + android:text="capture" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.498" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/textView2" /> - <!-- TODO: Update blank fragment layout --> <TextView - android:layout_width="match_parent" - android:layout_height="match_parent" - android:text="Twibbon Fragment" - android:textSize="26sp" - android:layout_gravity="center" /> + android:id="@+id/textView2" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="48dp" + android:layout_marginBottom="32dp" + android:text="Press the button to capture or retake!" + android:textAlignment="center" + android:textColor="#000000" + android:textSize="20sp" + app:layout_constraintBottom_toTopOf="@+id/button" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/frameLayout" + app:layout_constraintVertical_bias="0.49" /> -</FrameLayout> \ No newline at end of file +</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file