diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2b493d6d0776c6e27a466dffc0854c719f7bc84e..13ac1815da0d6f5ba6c8a7947dab5bd1f491cdc9 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -64,6 +64,7 @@ dependencies { implementation ("androidx.camera:camera-video:1.1.0") implementation ("androidx.camera:camera-view:1.1.0") implementation ("androidx.camera:camera-extensions:1.1.0") + implementation("androidx.room:room-common:2.6.1") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") diff --git a/app/src/main/java/com/pbd/psi/MainActivity.kt b/app/src/main/java/com/pbd/psi/MainActivity.kt index 927103875f6885593f077a46c0f3ccf10232d536..b2d54b2c14025894a0ea7cfcdb5d6e8728e5d4a8 100644 --- a/app/src/main/java/com/pbd/psi/MainActivity.kt +++ b/app/src/main/java/com/pbd/psi/MainActivity.kt @@ -4,20 +4,13 @@ import android.content.Intent import android.content.SharedPreferences import android.os.Bundle import android.view.Menu -import android.view.MenuItem -import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.navigation.fragment.NavHostFragment -import androidx.navigation.ui.AppBarConfiguration -import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController import com.google.android.material.bottomnavigation.BottomNavigationView import com.pbd.psi.databinding.ActivityMainBinding import com.pbd.psi.databinding.FragmentSettingsBinding import com.pbd.psi.services.BackgroundService -import android.content.res.ColorStateList - -import android.graphics.Color class MainActivity : AppCompatActivity() { companion object { @@ -63,6 +56,4 @@ class MainActivity : AppCompatActivity() { menuInflater.inflate(R.menu.bottom_nav_menu, menu) return true } - - } diff --git a/app/src/main/java/com/pbd/psi/api/ApiConfig.kt b/app/src/main/java/com/pbd/psi/api/ApiConfig.kt index 05479fccd7e973ac31f42076ee13d37b04839cb9..2a5d76a664165a79d7f2ba9a94d0663b12e5105c 100644 --- a/app/src/main/java/com/pbd/psi/api/ApiConfig.kt +++ b/app/src/main/java/com/pbd/psi/api/ApiConfig.kt @@ -15,4 +15,8 @@ object ApiConfig { val api: ApiService by lazy { retrofit.create(ApiService::class.java) } + + fun getApiService(): ApiService { + return retrofit.create(ApiService::class.java) + } } diff --git a/app/src/main/java/com/pbd/psi/api/ApiService.kt b/app/src/main/java/com/pbd/psi/api/ApiService.kt index 4654bbf18db73985d35eb4e90623314801d13e0e..340ef5d4c26b4e5f53ec702650ab2685056b40d7 100644 --- a/app/src/main/java/com/pbd/psi/api/ApiService.kt +++ b/app/src/main/java/com/pbd/psi/api/ApiService.kt @@ -3,12 +3,10 @@ package com.pbd.psi.api import com.pbd.psi.models.AuthRes import com.pbd.psi.models.LoginReq import com.pbd.psi.models.LoginRes +import com.pbd.psi.models.UploadRes +import okhttp3.MultipartBody import retrofit2.Call -import retrofit2.Response -import retrofit2.http.Body -import retrofit2.http.Header -import retrofit2.http.POST - +import retrofit2.http.* interface ApiService { @@ -21,4 +19,11 @@ interface ApiService { fun auth( @Header("Authorization") authHeader: String ): Call<AuthRes> + + @Multipart + @POST("/api/bill/upload") + fun uploadImage( + @Header("Authorization") token: String, + @Part image: MultipartBody.Part + ): Call<UploadRes> } \ No newline at end of file diff --git a/app/src/main/java/com/pbd/psi/models/UploadReq.kt b/app/src/main/java/com/pbd/psi/models/UploadReq.kt new file mode 100644 index 0000000000000000000000000000000000000000..285492d2947f34676ef9be740492d1cfcce79a62 --- /dev/null +++ b/app/src/main/java/com/pbd/psi/models/UploadReq.kt @@ -0,0 +1,5 @@ +package com.pbd.psi.models + +import okhttp3.RequestBody + +data class UploadReq(val file: RequestBody) diff --git a/app/src/main/java/com/pbd/psi/models/UploadRes.kt b/app/src/main/java/com/pbd/psi/models/UploadRes.kt new file mode 100644 index 0000000000000000000000000000000000000000..ed10035fea3f304b794d000d8b902ec887ada5d3 --- /dev/null +++ b/app/src/main/java/com/pbd/psi/models/UploadRes.kt @@ -0,0 +1,7 @@ +package com.pbd.psi.models + +data class UploadRes(val items: Items) + +data class Items(val items: List<Item>) + +data class Item(val name: String, val qty: Int, val price: Double) diff --git a/app/src/main/java/com/pbd/psi/ui/scan/ScanFragment.kt b/app/src/main/java/com/pbd/psi/ui/scan/ScanFragment.kt index b190738136af2a772e7357e5ee0d263b67de59ca..f06cbf85dd0a6b94864f250697928a2f5fddd6b5 100644 --- a/app/src/main/java/com/pbd/psi/ui/scan/ScanFragment.kt +++ b/app/src/main/java/com/pbd/psi/ui/scan/ScanFragment.kt @@ -2,7 +2,9 @@ package com.pbd.psi.ui.scan import android.Manifest import android.app.Activity +import android.content.Context import android.content.Intent +import android.graphics.Bitmap import android.graphics.BitmapFactory import android.graphics.drawable.BitmapDrawable import android.net.Uri @@ -21,7 +23,17 @@ import androidx.camera.lifecycle.ProcessCameraProvider import androidx.core.content.ContextCompat import androidx.core.view.isVisible import androidx.fragment.app.Fragment +import com.pbd.psi.LoginActivity +import com.pbd.psi.api.ApiConfig import com.pbd.psi.databinding.FragmentScanBinding +import com.pbd.psi.models.UploadRes +import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.MultipartBody +import okhttp3.RequestBody.Companion.toRequestBody +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response +import java.io.ByteArrayOutputStream class ScanFragment : Fragment() { @@ -78,6 +90,10 @@ class ScanFragment : Fragment() { previewMask() } + binding.sendButton?.setOnClickListener{ + uploadImage() + } + return root } @@ -150,6 +166,50 @@ class ScanFragment : Fragment() { } } + private fun uploadImage() { + var bitmap = (binding.scanView?.foreground as? BitmapDrawable)?.bitmap + if (bitmap == null) { + bitmap = (binding.scanView?.surfaceProvider as? BitmapDrawable)?.bitmap + } + val stream = ByteArrayOutputStream() + bitmap?.compress(Bitmap.CompressFormat.JPEG, 100, stream) + val byteArray = stream.toByteArray() + val requestBody = byteArray.toRequestBody("image/jpeg".toMediaTypeOrNull()) + + val token = requireActivity().getSharedPreferences(LoginActivity.SHARED_PREFS, Context.MODE_PRIVATE) + .getString(LoginActivity.TOKEN, "") + + if (token.isNullOrEmpty()) { + Toast.makeText(requireContext(), "Token not found. Please log in again.", Toast.LENGTH_SHORT).show() + return + } + + val imagePart = MultipartBody.Part.createFormData("file", "image.jpg", requestBody) + + val call = ApiConfig.api.uploadImage("Bearer $token", imagePart) + + call.enqueue(object : Callback<UploadRes> { + override fun onResponse(call: Call<UploadRes>, response: Response<UploadRes>) { + if (response.isSuccessful) { + val responseBody = response.body() + if (responseBody != null) { + val responseString = responseBody.toString() + Toast.makeText(requireContext(), "Image uploaded successfully! Response: $responseString", Toast.LENGTH_LONG).show() + } else { + Toast.makeText(requireContext(), "Image uploaded successfully!", Toast.LENGTH_SHORT).show() + } + previewMask() + } else { + Toast.makeText(requireContext(), "Failed to upload image. Error code: ${response.code()}", Toast.LENGTH_SHORT).show() + } + } + + override fun onFailure(call: Call<UploadRes>, t: Throwable) { + Log.e("UploadError", "Failed to upload image", t) + Toast.makeText(requireContext(), "Network error occurred. Please try again later.", Toast.LENGTH_SHORT).show() + } + }) + } override fun onDestroyView() { super.onDestroyView()