// inMOLA Analytics — Android SDK (tek dosya, bağımlılık yok). minSdk 16+.
//
// Kurulum: bu dosyayı projenize ekleyin (paket adını değiştirebilirsiniz). AndroidManifest.xml'de INTERNET izni olmalı:
//
// Application.onCreate(): InmolaAnalytics.init(this, "SITE_ANAHTARI")
// Ekran: InmolaAnalytics.screen("Ürün Detay")
// (Activity'ler kendiliğinden ekran sayılır; Compose / tek Activity'de screen() çağırın)
// Olay: InmolaAnalytics.event("sepete_ekle", "SKU-1")
// Satın alma: InmolaAnalytics.purchase("SIP-1001", 1499.90, "TRY",
// listOf(InmolaAnalytics.Item("SKU-1", "Ürün", 1499.90, 1)))
//
// Gizlilik: reklam kimliği / Android ID KULLANILMAZ, cihaza hiçbir şey yazılmaz, kişisel veri gönderilmez.
// Kayıtlar bellekte toplanır, ~10 sn'de bir ve uygulama arka plana geçerken gönderilir.
package com.inmola.analytics
import android.app.Activity
import android.app.Application
import android.os.Build
import android.os.Bundle
import java.net.HttpURLConnection
import java.util.Locale
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit
object InmolaAnalytics {
data class Item(val id: String, val name: String, val price: Double, val quantity: Int = 1)
/** Gönderim kapalı (ör. kullanıcı analitiği reddettiyse). Kapalıyken hiçbir şey toplanmaz. */
@Volatile var enabled = true
/** Activity'leri kendiliğinden ekran olarak say (sınıf adıyla, "Activity" eki atılır). */
@Volatile var autoScreens = true
private var core: Core? = null
private var started = 0
@JvmStatic @JvmOverloads
fun init(app: Application, siteKey: String, endpoint: String = Core.DEFAULT_ENDPOINT) {
if (core != null) return
val res = app.resources
val version = try { app.packageManager.getPackageInfo(app.packageName, 0).versionName ?: "" } catch (e: Exception) { "" }
val loc = Locale.getDefault()
val c = Core(siteKey, endpoint, mapOf(
"b" to app.packageName.lowercase(Locale.ROOT), "p" to "android", "ov" to (Build.VERSION.RELEASE ?: ""),
"dm" to (Build.MODEL ?: ""), "av" to version, "l" to loc.language + (if (loc.country.isNotEmpty()) "-" + loc.country else ""),
"tab" to (if (res.configuration.smallestScreenWidthDp >= 600) 1 else 0),
"w" to (res.displayMetrics.widthPixels / res.displayMetrics.density).toInt()))
core = c
app.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
override fun onActivityStarted(a: Activity) { if (started++ == 0) c.foreground() }
override fun onActivityStopped(a: Activity) { if (--started == 0) c.background() }
override fun onActivityResumed(a: Activity) { if (autoScreens) c.screen(a.javaClass.simpleName.removeSuffix("Activity").ifEmpty { "Main" }) }
override fun onActivityCreated(a: Activity, b: Bundle?) {}
override fun onActivityPaused(a: Activity) {}
override fun onActivitySaveInstanceState(a: Activity, b: Bundle) {}
override fun onActivityDestroyed(a: Activity) {}
})
}
/** Ekran açıldı. Elle çağırdığınızda Activity adıyla otomatik sayımı kapatmak için autoScreens = false yapın. */
@JvmStatic fun screen(name: String) { if (enabled) core?.screen(name) }
@JvmStatic @JvmOverloads fun event(name: String, detail: String = "") { if (enabled) core?.event(name, detail) }
@JvmStatic @JvmOverloads
fun purchase(transactionId: String, value: Double, currency: String, items: List- = emptyList()) {
if (enabled) core?.purchase(transactionId, value, currency, items)
}
/** Android'den bağımsız çekirdek (JVM'de test edilebilir): kuyruk, oturum, gönderim. */
class Core(private val key: String, private val endpoint: String, private val base: Map) {
companion object { const val DEFAULT_ENDPOINT = "https://inmola-analytics.iletisim-845.workers.dev/m" }
private val ex: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor()
private val pending = ArrayList