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 96fb416ec490bc656d7c15bbb71661af6a1f7830..990c70aaecf393c48a6b48b8e2e9ecedd88fa242 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 @@ -64,6 +64,22 @@ class Retrofit { 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>) { + if (response.isSuccessful) { + response.body()?.let { + callback.onSuccess(it) + } + } else { + callback.onFailure("Scan failed") + } + } + + override fun onFailure(call: Call<ItemsRoot>, t: Throwable) { + callback.onFailure("Failed to send request") + } + }) } } \ No newline at end of file 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 539c7795c230dd22e2dfa3dd9232491342e56822..e7a2e2613656f164565b3c7a41f48d4676f88076 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,14 +9,14 @@ data class LoginResponse ( val token: String ) -data class Item( +data class TransactionItem( val name: String, val qty: Int, val price: Double ) data class ItemsContainer( - val items: List<Item> + val items: List<TransactionItem> ) data class ItemsRoot( diff --git a/app/src/main/java/com/example/abe/ui/login/LoginActivity.kt b/app/src/main/java/com/example/abe/ui/login/LoginActivity.kt index 00288046b2652ea831f3dcde8df2d10009cb22d4..bd2385cc1a5268065fba188af94665bac7760b0f 100644 --- a/app/src/main/java/com/example/abe/ui/login/LoginActivity.kt +++ b/app/src/main/java/com/example/abe/ui/login/LoginActivity.kt @@ -9,7 +9,6 @@ import com.example.abe.R import com.example.abe.data.network.LoginResultCallback import com.example.abe.data.network.Retrofit import com.example.abe.databinding.ActivityLoginBinding -import com.example.abe.data.network.LoginResponse class LoginActivity : AppCompatActivity(), LoginResultCallback { 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 index df2788945e929d2b13230e2208b3999f170a1380..312146cec62d2c0dc85c3d10ed46f10904bf2817 100644 --- a/app/src/main/java/com/example/abe/ui/scanner/ScannerFragment.kt +++ b/app/src/main/java/com/example/abe/ui/scanner/ScannerFragment.kt @@ -3,7 +3,7 @@ package com.example.abe.ui.scanner import android.Manifest import android.app.Activity import android.app.Dialog -import android.content.ContentValues +import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.graphics.Color @@ -11,7 +11,6 @@ import android.graphics.drawable.ColorDrawable import android.net.Uri import android.os.Bundle import android.os.Environment -import android.provider.MediaStore import android.util.Log import android.view.LayoutInflater import android.view.View @@ -28,12 +27,16 @@ import androidx.fragment.app.Fragment import com.bumptech.glide.Glide import com.example.abe.R import androidx.camera.core.* +import androidx.fragment.app.viewModels +import com.example.abe.ABEApplication import com.example.abe.data.network.Retrofit import com.example.abe.data.network.ItemsRoot +import com.example.abe.data.network.TransactionItem 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.io.FileOutputStream import java.text.SimpleDateFormat import java.util.Locale import java.util.concurrent.ExecutorService @@ -46,6 +49,15 @@ class ScannerFragment : Fragment(), UploadResultCallback { 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 lateinit var user: String + + private val viewModel: ScannerViewModel by viewModels { + ScannerViewModelFactory((activity?.application as ABEApplication).repository) + } private val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> @@ -72,6 +84,9 @@ class ScannerFragment : Fragment(), UploadResultCallback { requestPermissions() + val sharedPref = activity?.getSharedPreferences(getString(R.string.preference_file_key), Context.MODE_PRIVATE) + user = sharedPref?.getString("user", "").toString() + binding.captureButton.setOnClickListener { takePicture() } @@ -185,12 +200,38 @@ class ScannerFragment : Fragment(), UploadResultCallback { } ) } + + private fun getLastLocation() { + fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireActivity()) + + if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { + fusedLocationClient.lastLocation + .addOnSuccessListener { location: android.location.Location? -> + location?.let { + latitude = location.latitude + longitude = location.longitude + Log.d(TAG, "Latitude: $latitude, Longitude: $longitude") + // Now you have latitude and longitude, pass them to insertTransaction + } + } + .addOnFailureListener { e -> + Log.e(TAG, "Failed to get location: ${e.message}", e) + } + } else { + // Handle the case where location permission is not granted + Log.e(TAG, "Location permission not granted") + // You may want to request the permission again or handle it in some other way + } + } + override fun onSuccess(uploadResponse: ItemsRoot) { - // TODO send the data to database + uploadResponse.items.items.forEach {item -> + viewModel.insertTransaction(user, item, latitude, longitude) + } } override fun onFailure(errorMessage: String) { - // TODO handle failed to get response + println("Scan Error! $errorMessage") } private fun openGallery() { @@ -223,6 +264,7 @@ class ScannerFragment : Fragment(), UploadResultCallback { super.onViewCreated(view, savedInstanceState) if (allPermissionsGranted()) { startCamera() + getLastLocation() } else { ActivityCompat.requestPermissions( requireActivity(), REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS) 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..8a6946ebac265dc16ddd4b2d88a3cdbc0b9e1da1 --- /dev/null +++ b/app/src/main/java/com/example/abe/ui/scanner/ScannerViewModel.kt @@ -0,0 +1,40 @@ +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) = 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 = "Unknown", + ) + 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") + } +}