diff --git a/app/src/main/java/id/ac/ubharajaya/sistemakademik/data/MataKuliah.kt b/app/src/main/java/id/ac/ubharajaya/sistemakademik/data/MataKuliah.kt index dd00b9c..d994df2 100644 --- a/app/src/main/java/id/ac/ubharajaya/sistemakademik/data/MataKuliah.kt +++ b/app/src/main/java/id/ac/ubharajaya/sistemakademik/data/MataKuliah.kt @@ -1,2 +1,6 @@ package id.ac.ubharajaya.sistemakademik.data +data class MataKuliah( + val kode: String, + val nama: String +) \ No newline at end of file diff --git a/app/src/main/java/id/ac/ubharajaya/sistemakademik/data/UserProfile.kt b/app/src/main/java/id/ac/ubharajaya/sistemakademik/data/UserProfile.kt index ac88714..d83b19c 100644 --- a/app/src/main/java/id/ac/ubharajaya/sistemakademik/data/UserProfile.kt +++ b/app/src/main/java/id/ac/ubharajaya/sistemakademik/data/UserProfile.kt @@ -11,6 +11,12 @@ data class AbsensiData( val longitude: Double, val timestamp: Long, val fotoBase64: String, + + // 🔽 FIELD BARU (WAJIB DITARUH SEBELUM DEFAULT VALUE) + val kodeMatkul: String, + val namaMatkul: String, + + // 🔽 FIELD DENGAN DEFAULT VALUE HARUS PALING BAWAH val alamat: String = "Alamat tidak tersedia" ) diff --git a/app/src/main/java/id/ac/ubharajaya/sistemakademik/ui/fragments/AbsensiFragment.kt b/app/src/main/java/id/ac/ubharajaya/sistemakademik/ui/fragments/AbsensiFragment.kt index af8bbb3..608cb32 100644 --- a/app/src/main/java/id/ac/ubharajaya/sistemakademik/ui/fragments/AbsensiFragment.kt +++ b/app/src/main/java/id/ac/ubharajaya/sistemakademik/ui/fragments/AbsensiFragment.kt @@ -11,10 +11,7 @@ import android.util.Base64 import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.Button -import android.widget.ImageView -import android.widget.TextView -import android.widget.Toast +import android.widget.* import androidx.activity.result.contract.ActivityResultContracts import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment @@ -23,6 +20,8 @@ import com.google.android.gms.location.LocationServices import id.ac.ubharajaya.sistemakademik.R import id.ac.ubharajaya.sistemakademik.data.AbsensiData import id.ac.ubharajaya.sistemakademik.data.DataHolder +import id.ac.ubharajaya.sistemakademik.data.MataKuliah +import id.ac.ubharajaya.sistemakademik.utils.DummyData import java.io.ByteArrayOutputStream class AbsensiFragment : Fragment() { @@ -31,59 +30,48 @@ class AbsensiFragment : Fragment() { private lateinit var tvLokasi: TextView private lateinit var btnAmbilFoto: Button private lateinit var btnLanjut: Button + private lateinit var spinnerMatkul: Spinner private var foto: Bitmap? = null private var latitude: Double? = null private var longitude: Double? = null + private var selectedMatkul: MataKuliah? = null private val fusedLocationClient by lazy { LocationServices.getFusedLocationProviderClient(requireActivity()) } - // Permission launcher untuk lokasi - private val locationPermissionLauncher = registerForActivityResult( - ActivityResultContracts.RequestPermission() - ) { granted -> - if (granted) { - ambilLokasiGPS() - } else { - Toast.makeText(context, "Izin lokasi ditolak", Toast.LENGTH_SHORT).show() + // ===== Permission Launcher ===== + private val locationPermissionLauncher = + registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted -> + if (granted) ambilLokasiGPS() + else Toast.makeText(context, "Izin lokasi ditolak", Toast.LENGTH_SHORT).show() } - } - // Camera launcher - private val cameraLauncher = registerForActivityResult( - ActivityResultContracts.StartActivityForResult() - ) { result -> - if (result.resultCode == Activity.RESULT_OK) { - val bitmap = result.data?.extras?.get("data") as? Bitmap - if (bitmap != null) { - foto = bitmap - ivPreview.setImageBitmap(bitmap) - cekKelengkapanData() - Toast.makeText(context, "Foto berhasil diambil!", Toast.LENGTH_SHORT).show() + private val cameraPermissionLauncher = + registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted -> + if (granted) bukaKamera() + else Toast.makeText(context, "Izin kamera ditolak", Toast.LENGTH_SHORT).show() + } + + private val cameraLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == Activity.RESULT_OK) { + val bitmap = result.data?.extras?.get("data") as? Bitmap + bitmap?.let { + foto = it + ivPreview.setImageBitmap(it) + cekKelengkapanData() + Toast.makeText(context, "Foto berhasil diambil!", Toast.LENGTH_SHORT).show() + } } } - } - - // Permission launcher untuk kamera - private val cameraPermissionLauncher = registerForActivityResult( - ActivityResultContracts.RequestPermission() - ) { granted -> - if (granted) { - bukaKamera() - } else { - Toast.makeText(context, "Izin kamera ditolak", Toast.LENGTH_SHORT).show() - } - } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View? { - return inflater.inflate(R.layout.fragment_absensi, container, false) - } + ): View = inflater.inflate(R.layout.fragment_absensi, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -92,87 +80,106 @@ class AbsensiFragment : Fragment() { tvLokasi = view.findViewById(R.id.tvLokasi) btnAmbilFoto = view.findViewById(R.id.btnAmbilFoto) btnLanjut = view.findViewById(R.id.btnLanjutPreview) + spinnerMatkul = view.findViewById(R.id.spinnerMatkul) - // Cek profile sudah diisi atau belum - if (DataHolder.userProfile.nama.isEmpty()) { - Toast.makeText(context, "Isi profile dulu di tab Profil!", Toast.LENGTH_LONG).show() - } - - // Request permission lokasi + setupSpinnerMatkul() requestLocationPermission() - btnAmbilFoto.setOnClickListener { - requestCameraPermission() - } + btnAmbilFoto.setOnClickListener { requestCameraPermission() } btnLanjut.setOnClickListener { - if (foto != null && latitude != null && longitude != null) { - simpanDataSementara() - findNavController().navigate(R.id.action_absensi_to_preview) - } + simpanDataSementara() + findNavController().navigate(R.id.action_absensi_to_preview) } } + // ===== Mata Kuliah ===== + private fun setupSpinnerMatkul() { + val matkulList = DummyData.mataKuliahList + + val adapter = ArrayAdapter( + requireContext(), + android.R.layout.simple_spinner_dropdown_item, + matkulList.map { "${it.kode} - ${it.nama}" } + ) + + spinnerMatkul.adapter = adapter + + spinnerMatkul.onItemSelectedListener = + object : AdapterView.OnItemSelectedListener { + override fun onItemSelected( + parent: AdapterView<*>, view: View?, position: Int, id: Long + ) { + selectedMatkul = matkulList[position] + cekKelengkapanData() + } + + override fun onNothingSelected(parent: AdapterView<*>) { + selectedMatkul = null + cekKelengkapanData() + } + } + } + + // ===== Location ===== private fun requestLocationPermission() { - when { - ContextCompat.checkSelfPermission( + if (ContextCompat.checkSelfPermission( requireContext(), Manifest.permission.ACCESS_FINE_LOCATION - ) == PackageManager.PERMISSION_GRANTED -> { - ambilLokasiGPS() - } - else -> { - locationPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION) - } + ) == PackageManager.PERMISSION_GRANTED + ) { + ambilLokasiGPS() + } else { + locationPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION) } } private fun ambilLokasiGPS() { - try { - fusedLocationClient.lastLocation.addOnSuccessListener { location -> - if (location != null) { - latitude = location.latitude - longitude = location.longitude - tvLokasi.text = "📍 GPS Ready\nLat: ${location.latitude}\nLon: ${location.longitude}" - cekKelengkapanData() - } else { - tvLokasi.text = "❌ Lokasi tidak tersedia\nHidupkan GPS" - } + fusedLocationClient.lastLocation.addOnSuccessListener { location -> + if (location != null) { + latitude = location.latitude + longitude = location.longitude + tvLokasi.text = + "📍 GPS Ready\nLat: ${location.latitude}\nLon: ${location.longitude}" + cekKelengkapanData() + } else { + tvLokasi.text = "❌ Lokasi tidak tersedia" } - } catch (e: SecurityException) { - Toast.makeText(context, "Error: ${e.message}", Toast.LENGTH_SHORT).show() } } + // ===== Camera ===== private fun requestCameraPermission() { - when { - ContextCompat.checkSelfPermission( + if (ContextCompat.checkSelfPermission( requireContext(), Manifest.permission.CAMERA - ) == PackageManager.PERMISSION_GRANTED -> { - bukaKamera() - } - else -> { - cameraPermissionLauncher.launch(Manifest.permission.CAMERA) - } + ) == PackageManager.PERMISSION_GRANTED + ) { + bukaKamera() + } else { + cameraPermissionLauncher.launch(Manifest.permission.CAMERA) } } private fun bukaKamera() { - val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE) - cameraLauncher.launch(intent) + cameraLauncher.launch(Intent(MediaStore.ACTION_IMAGE_CAPTURE)) } + // ===== Validation ===== private fun cekKelengkapanData() { - btnLanjut.isEnabled = foto != null && latitude != null && longitude != null + btnLanjut.isEnabled = + foto != null && + latitude != null && + longitude != null && + selectedMatkul != null } + // ===== Save ===== private fun simpanDataSementara() { val bitmap = foto ?: return val lat = latitude ?: return val lon = longitude ?: return - - val fotoBase64 = bitmapToBase64(bitmap) + val matkul = selectedMatkul ?: return DataHolder.currentAbsensi = AbsensiData( nama = DataHolder.userProfile.nama, @@ -180,8 +187,10 @@ class AbsensiFragment : Fragment() { latitude = lat, longitude = lon, timestamp = System.currentTimeMillis(), - fotoBase64 = fotoBase64, - alamat = "Alamat akan diambil saat preview" + fotoBase64 = bitmapToBase64(bitmap), + alamat = "Alamat akan diambil saat preview", + kodeMatkul = matkul.kode, + namaMatkul = matkul.nama ) } diff --git a/app/src/main/java/id/ac/ubharajaya/sistemakademik/ui/fragments/PreviewFragment.kt b/app/src/main/java/id/ac/ubharajaya/sistemakademik/ui/fragments/PreviewFragment.kt index 3a84f2d..29cc891 100644 --- a/app/src/main/java/id/ac/ubharajaya/sistemakademik/ui/fragments/PreviewFragment.kt +++ b/app/src/main/java/id/ac/ubharajaya/sistemakademik/ui/fragments/PreviewFragment.kt @@ -123,17 +123,38 @@ class PreviewFragment : Fragment() { conn.doOutput = true val json = JSONObject().apply { + + // 1️⃣ HARUS ADA + put("timestamp", absensi.timestamp) + + // 2️⃣ IP address (kalau belum ada, kirim dummy) + put("ip_addr", "android") + + // 3️⃣ Identitas put("npm", absensi.npm) put("nama", absensi.nama) + + // 4️⃣ Lokasi put("latitude", absensi.latitude) put("longitude", absensi.longitude) - put("timestamp", absensi.timestamp) - put("foto_base64", absensi.fotoBase64) - put("address", absensi.alamat) - put("distance_from_campus", 0) + + // 5️⃣ MATA KULIAH (INI YANG KOSONG KEMARIN) + put("mata_kuliah", absensi.namaMatkul) + // atau kalau mau sekalian kode: + // put("mata_kuliah", "${absensi.kodeMatkul} - ${absensi.namaMatkul}") + + // 6️⃣ Photo (boleh string apa aja / URL / label) + put("photo", "camera") + + // 7️⃣ Status put("status", "hadir") + + // 8️⃣ FOTO BASE64 + put("foto_base64", absensi.fotoBase64) } + + conn.outputStream.use { it.write(json.toString().toByteArray()) } diff --git a/app/src/main/java/id/ac/ubharajaya/sistemakademik/utils/DummyData.kt b/app/src/main/java/id/ac/ubharajaya/sistemakademik/utils/DummyData.kt index b94cdbb..b854529 100644 --- a/app/src/main/java/id/ac/ubharajaya/sistemakademik/utils/DummyData.kt +++ b/app/src/main/java/id/ac/ubharajaya/sistemakademik/utils/DummyData.kt @@ -1,2 +1,11 @@ package id.ac.ubharajaya.sistemakademik.utils +import id.ac.ubharajaya.sistemakademik.data.MataKuliah + +object DummyData { + val mataKuliahList = listOf( + MataKuliah("IF301", "Pemrograman Mobile"), + MataKuliah("IF302", "Kecerdasan Buatan"), + MataKuliah("IF303", "Basis Data") + ) +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_absensi.xml b/app/src/main/res/layout/fragment_absensi.xml index 56d0dc6..7b4d100 100644 --- a/app/src/main/res/layout/fragment_absensi.xml +++ b/app/src/main/res/layout/fragment_absensi.xml @@ -32,6 +32,13 @@ android:textAlignment="center" android:layout_marginBottom="32dp"/> + + +