diff --git a/.idea/misc.xml b/.idea/misc.xml index 0ad17cbd33a2f389d524bc4bfef9c52e1f7ab490..f1044879e31aa73a3e757a2f81a68e7c26bd222a 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <project version="4"> <component name="ExternalStorageConfigurationManager" enabled="true" /> - <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK"> + <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK"> <output url="file://$PROJECT_DIR$/build/classes" /> </component> <component name="ProjectType"> diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a20d57ed3c0bc8cac41cee5a5d5ce1c215bc4a8d..e40a96212e0ca27ed185ec5e1d5de957ca615d08 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -64,6 +64,8 @@ dependencies { //QR COde implementation ("com.github.yuriy-budiyev:code-scanner:2.3.0") + implementation ("com.journeyapps:zxing-android-embedded:4.2.0") + implementation ("com.google.zxing:core:3.4.1") // note // Graph implementation("com.github.PhilJay:MPAndroidChart:v3.1.0") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1332daba8108a151989a0ad68341ece09f1de182..d5df3c05c5c719ea7e646e892b520d138135fd98 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,15 +7,14 @@ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> - <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" - android:maxSdkVersion="32" /> - <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" - android:maxSdkVersion="32" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <uses-permission android:name="android.permission.CAMERA"/> + <uses-sdk tools:overrideLibrary="com.google.zxing.client.android" /> + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-feature android:name="android.hardware.camera" @@ -25,6 +24,7 @@ <application android:name=".BondowowoApp" android:allowBackup="true" + android:requestLegacyExternalStorage="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" @@ -50,6 +50,10 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> + <activity + android:name="com.journeyapps.barcodescanner.CaptureActivity" + android:screenOrientation="fullSensor" + tools:replace="screenOrientation" /> <activity android:name=".ui.settings.ExportToFileActivity" /> <activity android:name=".ui.settings.SendEmailActivity" /> diff --git a/app/src/main/java/com/atm/bondowowo/ui/scan/ScanFragment.kt b/app/src/main/java/com/atm/bondowowo/ui/scan/ScanFragment.kt index 13d2dbb861c9d51b5a496376f8c0f56cb6277be3..ce83385dda48152622b0ff4d94614de1d10680f6 100644 --- a/app/src/main/java/com/atm/bondowowo/ui/scan/ScanFragment.kt +++ b/app/src/main/java/com/atm/bondowowo/ui/scan/ScanFragment.kt @@ -1,12 +1,23 @@ package com.atm.bondowowo.ui.scan import android.Manifest +import android.app.Activity +import android.app.AlertDialog +import android.content.Intent import android.content.pm.PackageManager +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.net.Uri 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.Button +import android.widget.TextView import android.widget.Toast +import androidx.activity.result.contract.ActivityResultContracts import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment @@ -14,8 +25,25 @@ import com.atm.bondowowo.R import com.budiyev.android.codescanner.CodeScanner import com.budiyev.android.codescanner.CodeScannerView import com.budiyev.android.codescanner.DecodeCallback +import com.google.zxing.BinaryBitmap +import com.google.zxing.ChecksumException +import com.google.zxing.FormatException +import com.google.zxing.LuminanceSource +import com.google.zxing.MultiFormatReader +import com.google.zxing.NotFoundException +import com.google.zxing.RGBLuminanceSource +import com.google.zxing.Reader +import com.google.zxing.common.HybridBinarizer +import java.io.BufferedInputStream +import java.io.File +import java.io.FileInputStream +import java.io.InputStream class ScanFragment : Fragment() { + private lateinit var tvResult: TextView + private var WRITE_EXTERNAL_STORAGE_PERMISSION_CODE: Int = 1 + private var READ_EXTERNAL_STORAGE_PERMISSION_CODE: Int = 2 + private val CAMERA_PERMISSION_REQUEST_CODE = 100 private lateinit var codeScanner: CodeScanner @@ -26,6 +54,12 @@ class ScanFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val scannerView = view.findViewById<CodeScannerView>(R.id.scanner) + tvResult = view.findViewById(R.id.tv_result) // + + val btnUpload = view.findViewById<Button>(R.id.btn_upload) + btnUpload.setOnClickListener { + openGallery() + } // Check camera permission if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { @@ -33,13 +67,71 @@ class ScanFragment : Fragment() { } else { initializeCodeScanner(scannerView) } + + // for file + if (ContextCompat.checkSelfPermission(requireContext(),Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) { + ActivityCompat.requestPermissions( + requireActivity(), + arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), + WRITE_EXTERNAL_STORAGE_PERMISSION_CODE + ) + } else if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) { + ActivityCompat.requestPermissions( + requireActivity(), + arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), + READ_EXTERNAL_STORAGE_PERMISSION_CODE + ) + } + } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) { + if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + val scannerView = requireView().findViewById<CodeScannerView>(R.id.scanner) + initializeCodeScanner(scannerView) + } else { + Toast.makeText(requireContext(), "Camera permission denied", Toast.LENGTH_SHORT).show() + } + } else if (requestCode == WRITE_EXTERNAL_STORAGE_PERMISSION_CODE) { + if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_DENIED) { + Toast.makeText( + requireContext(), + "Anda perlu memberikan semua izin untuk menggunakan aplikasi ini.", + Toast.LENGTH_SHORT + ).show() + requireActivity().finish() + } + } else if (requestCode == READ_EXTERNAL_STORAGE_PERMISSION_CODE) { + if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_DENIED) { + Toast.makeText( + requireContext(), + "Anda perlu memberikan semua izin untuk menggunakan aplikasi ini.", + Toast.LENGTH_SHORT + ).show() + requireActivity().finish() + } + } } private fun initializeCodeScanner(scannerView: CodeScannerView) { codeScanner = CodeScanner(requireActivity(), scannerView) + codeScanner.startPreview() + codeScanner.decodeCallback = DecodeCallback { requireActivity().runOnUiThread { + val contents = it.text + tvResult.text = contents Toast.makeText(requireContext(), "Scanned: ${it.text}", Toast.LENGTH_LONG).show() + + val scanOptions = arrayOf<String>("Ya", "Tidak") + AlertDialog.Builder(requireContext()) + .setTitle("Scan Berhasil!\nApakah ingin mengulagi proses Scan?") + .setItems(scanOptions) {_, which -> when (which) { + 0 -> codeScanner.startPreview() + 1 -> setToTransaction() + } } + .create().show() } } scannerView.setOnClickListener { @@ -47,15 +139,85 @@ class ScanFragment : Fragment() { } } - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - if (requestCode == CAMERA_PERMISSION_REQUEST_CODE) { - if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - val scannerView = requireView().findViewById<CodeScannerView>(R.id.scanner) - initializeCodeScanner(scannerView) + private fun setToTransaction() { + Log.d("TODO", "next to transaction") + TODO("Not yet implemented") + } + + private fun openGallery() { + Log.d("ScanFragment", "Fungsi openGallery() dipanggil") + val galleryIntent = + Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) + resultLauncherGallery.launch(galleryIntent) + } + + private val resultLauncherGallery = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == Activity.RESULT_OK) { + val data: Intent? = result.data + + val imageUri = data!!.data!! + val imagePath = convertMediaUriToPath(imageUri) + Log.d("ScanFragment", "Berhasil convertMediaUriToPath") + val imgFile = File(imagePath) + scanImageQRCode(imgFile) + Log.d("ScanFragment", "Berhasil scanImageQRCode") } else { - Toast.makeText(requireContext(), "Camera permission denied", Toast.LENGTH_SHORT).show() + Toast.makeText(requireContext(), "Result Not Found", Toast.LENGTH_LONG).show() } } + + private fun convertMediaUriToPath(uri: Uri): String { + val proj = arrayOf(MediaStore.Images.Media.DATA) + val cursor = requireActivity().contentResolver.query(uri, proj, null, null, null) + val columnIndex = cursor!!.getColumnIndexOrThrow(MediaStore.Images.Media.DATA) + cursor.moveToFirst() + val path = cursor.getString(columnIndex) + cursor.close() + return path + } + + private fun scanImageQRCode(file: File) { + val inputStream: InputStream = BufferedInputStream(FileInputStream(file)) + val bitmap = BitmapFactory.decodeStream(inputStream) + val decoded = scanQRImage(bitmap) + Log.i("QrTest", "Decoded string=$decoded") + } + + private fun scanQRImage(bMap: Bitmap): String? { + var contents: String? = null + val intArray = IntArray(bMap.width * bMap.height) + //copy pixel data from the Bitmap into the 'intArray' array + bMap.getPixels(intArray, 0, bMap.width, 0, 0, bMap.width, bMap.height) + val source: LuminanceSource = RGBLuminanceSource(bMap.width, bMap.height, intArray) + val bitmap = BinaryBitmap(HybridBinarizer(source)) + val reader: Reader = MultiFormatReader() + try { + val result: com.google.zxing.Result = reader.decode(bitmap) + Log.d("scanQRImage", "berhasil yang bagian Result") + contents = result.text + // TODO MASUKIN BE DISINI + + tvResult.text = contents + + val scanOptions = arrayOf<String>("Ya", "Tidak") + AlertDialog.Builder(requireContext()) + .setTitle("Scan Berhasil!\nApakah ingin mengulagi proses Scan?") + .setItems(scanOptions) {_, which -> when (which) { + 0 -> codeScanner.startPreview() + 1 -> setToTransaction() + } } + .create().show() + + } catch (e: Exception) { + Log.e("QrTest", "Error decoding qr code", e) + Toast.makeText( + requireContext(), + "Error decoding QR Code, Mohon pilih gambar QR Code yang benar!", + Toast.LENGTH_SHORT + ).show() + } + return contents } + } diff --git a/app/src/main/res/layout/fragment_scan.xml b/app/src/main/res/layout/fragment_scan.xml index 36b25531628c364f13e92516cd573573bdeaba13..b55566c2f84d7bbc7d926f81ab12fc799c37e21b 100644 --- a/app/src/main/res/layout/fragment_scan.xml +++ b/app/src/main/res/layout/fragment_scan.xml @@ -40,12 +40,23 @@ android:layout_height="600dp" app:autoFocusButtonVisible="true"/> + <Button + android:id="@+id/btn_upload" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginTop="5dp" + + android:text="Upload File" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toEndOf="parent" /> + <TextView - android:id="@+id/tv_output" + android:id="@+id/tv_result" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="20dp" - android:text="The result is here" + android:layout_marginTop="1dp" + android:text="..." android:textAlignment="center" android:textSize="20sp" android:textColor="#A92B"/> diff --git a/build.gradle.kts b/build.gradle.kts index 3893b8309e82cda878bd47d6c643304e6c98b23d..83773511e0af7d549b6f7d6225b49850fc1fca51 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,4 +3,12 @@ plugins { id("com.android.application") version "8.2.1" apply false id("org.jetbrains.kotlin.android") version "1.9.22" apply false -} \ No newline at end of file +} + +// QR +//allprojects { +// repositories { +// google() +// mavenCentral() +// } +//} \ No newline at end of file