Raka Herlambang
This commit is contained in:
parent
ed435ffbc1
commit
db4277dace
@ -5,6 +5,7 @@ import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Bitmap
|
||||
import android.location.Location
|
||||
import android.os.Bundle
|
||||
import android.provider.MediaStore
|
||||
import android.util.Base64
|
||||
@ -14,10 +15,13 @@ import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.ContextCompat
|
||||
@ -29,6 +33,21 @@ import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
/* ================= KONFIGURASI LOKASI ================= */
|
||||
|
||||
const val KAMPUS_LAT = -6.222967558410948
|
||||
const val KAMPUS_LON = 107.00931291609834
|
||||
const val MAX_RADIUS = 1000 // meter
|
||||
|
||||
fun hitungJarak(
|
||||
lat1: Double, lon1: Double,
|
||||
lat2: Double, lon2: Double
|
||||
): Float {
|
||||
val hasil = FloatArray(1)
|
||||
Location.distanceBetween(lat1, lon1, lat2, lon2, hasil)
|
||||
return hasil[0]
|
||||
}
|
||||
|
||||
/* ================= UTIL ================= */
|
||||
|
||||
fun bitmapToBase64(bitmap: Bitmap): String {
|
||||
@ -39,14 +58,17 @@ fun bitmapToBase64(bitmap: Bitmap): String {
|
||||
|
||||
fun kirimKeN8n(
|
||||
context: ComponentActivity,
|
||||
npm: String,
|
||||
nama: String,
|
||||
mataKuliah: String,
|
||||
latitude: Double,
|
||||
longitude: Double,
|
||||
foto: Bitmap
|
||||
foto: Bitmap,
|
||||
status: String
|
||||
) {
|
||||
thread {
|
||||
try {
|
||||
val url = URL("https://n8n.lab.ubharajaya.ac.id/webhook/23c6993d-1792-48fb-ad1c-ffc78a3e6254")
|
||||
// test URL val url = URL("https://n8n.lab.ubharajaya.ac.id/webhook-test/23c6993d-1792-48fb-ad1c-ffc78a3e6254")
|
||||
val conn = url.openConnection() as HttpURLConnection
|
||||
|
||||
conn.requestMethod = "POST"
|
||||
@ -54,11 +76,13 @@ fun kirimKeN8n(
|
||||
conn.doOutput = true
|
||||
|
||||
val json = JSONObject().apply {
|
||||
put("npm", "12345")
|
||||
put("nama","Arif R D")
|
||||
put("npm", npm)
|
||||
put("nama", nama)
|
||||
put("mata_kuliah", mataKuliah)
|
||||
put("latitude", latitude)
|
||||
put("longitude", longitude)
|
||||
put("timestamp", System.currentTimeMillis())
|
||||
put("status", status)
|
||||
put("foto_base64", bitmapToBase64(foto))
|
||||
}
|
||||
|
||||
@ -72,9 +96,9 @@ fun kirimKeN8n(
|
||||
Toast.makeText(
|
||||
context,
|
||||
if (responseCode == 200)
|
||||
"Absensi diterima server"
|
||||
"Absensi $status"
|
||||
else
|
||||
"Absensi ditolak server",
|
||||
"Server menolak absensi",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
@ -123,6 +147,10 @@ fun AbsensiScreen(
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
var npm by remember { mutableStateOf("") }
|
||||
var nama by remember { mutableStateOf("") }
|
||||
var mataKuliah by remember { mutableStateOf("") }
|
||||
|
||||
var lokasi by remember { mutableStateOf("Koordinat: -") }
|
||||
var latitude by remember { mutableStateOf<Double?>(null) }
|
||||
var longitude by remember { mutableStateOf<Double?>(null) }
|
||||
@ -138,14 +166,12 @@ fun AbsensiScreen(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { granted ->
|
||||
if (granted) {
|
||||
|
||||
if (
|
||||
ContextCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
|
||||
fusedLocationClient.lastLocation
|
||||
.addOnSuccessListener { location ->
|
||||
if (location != null) {
|
||||
@ -157,11 +183,7 @@ fun AbsensiScreen(
|
||||
lokasi = "Lokasi tidak tersedia"
|
||||
}
|
||||
}
|
||||
.addOnFailureListener {
|
||||
lokasi = "Gagal mengambil lokasi"
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
Toast.makeText(
|
||||
context,
|
||||
@ -178,8 +200,7 @@ fun AbsensiScreen(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
val bitmap =
|
||||
result.data?.extras?.getParcelable("data", Bitmap::class.java)
|
||||
val bitmap = result.data?.extras?.get("data") as? Bitmap
|
||||
if (bitmap != null) {
|
||||
foto = bitmap
|
||||
Toast.makeText(
|
||||
@ -187,6 +208,12 @@ fun AbsensiScreen(
|
||||
"Foto berhasil diambil",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
} else {
|
||||
Toast.makeText(
|
||||
context,
|
||||
"Gagal mengambil foto",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -196,8 +223,7 @@ fun AbsensiScreen(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { granted ->
|
||||
if (granted) {
|
||||
val intent =
|
||||
Intent(MediaStore.ACTION_IMAGE_CAPTURE)
|
||||
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
|
||||
cameraLauncher.launch(intent)
|
||||
} else {
|
||||
Toast.makeText(
|
||||
@ -208,8 +234,6 @@ fun AbsensiScreen(
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Request Awal ===== */
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
locationPermissionLauncher.launch(
|
||||
Manifest.permission.ACCESS_FINE_LOCATION
|
||||
@ -232,9 +256,32 @@ fun AbsensiScreen(
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
OutlinedTextField(
|
||||
value = npm,
|
||||
onValueChange = { npm = it },
|
||||
label = { Text("NPM") },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
value = nama,
|
||||
onValueChange = { nama = it },
|
||||
label = { Text("Nama") },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
OutlinedTextField(
|
||||
value = mataKuliah,
|
||||
onValueChange = { mataKuliah = it },
|
||||
label = { Text("Mata Kuliah") },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
Text(text = lokasi)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
Button(
|
||||
onClick = {
|
||||
@ -247,21 +294,66 @@ fun AbsensiScreen(
|
||||
Text("Ambil Foto")
|
||||
}
|
||||
|
||||
/* ===== PREVIEW FOTO ===== */
|
||||
|
||||
if (foto != null) {
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Image(
|
||||
bitmap = foto!!.asImageBitmap(),
|
||||
contentDescription = "Preview Foto Absensi",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(220.dp),
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
Button(
|
||||
onClick = {
|
||||
if (latitude != null && longitude != null && foto != null) {
|
||||
kirimKeN8n(
|
||||
activity,
|
||||
if (
|
||||
npm.isNotEmpty() &&
|
||||
nama.isNotEmpty() &&
|
||||
mataKuliah.isNotEmpty() &&
|
||||
latitude != null &&
|
||||
longitude != null &&
|
||||
foto != null
|
||||
) {
|
||||
|
||||
val jarak = hitungJarak(
|
||||
latitude!!,
|
||||
longitude!!,
|
||||
foto!!
|
||||
KAMPUS_LAT,
|
||||
KAMPUS_LON
|
||||
)
|
||||
|
||||
val status =
|
||||
if (jarak <= MAX_RADIUS) "HADIR" else "DITOLAK"
|
||||
|
||||
if (status == "HADIR") {
|
||||
kirimKeN8n(
|
||||
activity,
|
||||
npm,
|
||||
nama,
|
||||
mataKuliah,
|
||||
latitude!!,
|
||||
longitude!!,
|
||||
foto!!,
|
||||
status
|
||||
)
|
||||
} else {
|
||||
Toast.makeText(
|
||||
context,
|
||||
"Absensi ditolak (di luar area)",
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
|
||||
} else {
|
||||
Toast.makeText(
|
||||
context,
|
||||
"Lokasi atau foto belum lengkap",
|
||||
"Data absensi belum lengkap",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ pluginManagement {
|
||||
}
|
||||
}
|
||||
dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositoriesMode.set(org.gradle.api.initialization.resolve.RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
@ -21,4 +21,3 @@ dependencyResolutionManagement {
|
||||
|
||||
rootProject.name = "Sistem Akademik"
|
||||
include(":app")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user