package com.dano.test1 import android.content.res.Configuration import android.net.ConnectivityManager import android.net.Network import android.net.NetworkCapabilities import android.net.NetworkRequest import android.os.Bundle import android.view.View import android.widget.EditText import android.widget.LinearLayout import android.widget.ProgressBar import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import java.io.File class MainActivity : AppCompatActivity() { private lateinit var openingScreenHandler: HandlerOpeningScreen var isInQuestionnaire: Boolean = false var isFirstQuestionnairePage: Boolean = false private var progress: ProgressBar? = null // LIVE: Network-Callback (optional für Statusleiste) private var netCb: ConnectivityManager.NetworkCallback? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // === Offline-Start ermöglichen === // Bedingung: gespeicherter User/Token UND lokale DB vorhanden -> direkt OpeningScreen val hasCreds = !TokenStore.getUsername(this).isNullOrBlank() && !TokenStore.getToken(this).isNullOrBlank() val hasDb = hasLocalDb() if (hasCreds && hasDb) { openingScreenHandler = HandlerOpeningScreen(this) openingScreenHandler.init() return } // Sonst: Login-Dialog -> Login -> DB (einmalig) laden -> OpeningScreen showLoginThenDownload() } /** Prüft, ob die lokale DB-Datei vorhanden ist. */ private fun hasLocalDb(): Boolean { val dbFile = getDatabasePath("questionnaire_database") return dbFile != null && dbFile.exists() && dbFile.length() > 0 } /** Zeigt den Login-Dialog an, führt Login aus und lädt danach einmalig die DB. */ private fun showLoginThenDownload() { val container = LinearLayout(this).apply { orientation = LinearLayout.VERTICAL setPadding(dp(20), dp(8), dp(20), 0) } val etUser = EditText(this).apply { hint = "Username" setSingleLine() } val etPass = EditText(this).apply { hint = "Passwort" setSingleLine() inputType = android.text.InputType.TYPE_CLASS_TEXT or android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD } container.addView(etUser) container.addView(etPass) val dialog = AlertDialog.Builder(this) .setTitle("Login erforderlich") .setView(container) .setCancelable(false) .setPositiveButton("Login") { _, _ -> val user = etUser.text.toString().trim() val pass = etPass.text.toString() if (user.isEmpty() || pass.isEmpty()) { Toast.makeText(this, "Bitte Username & Passwort eingeben", Toast.LENGTH_SHORT).show() showLoginThenDownload() return@setPositiveButton } showBusy(true) LoginManager.loginUserWithCredentials( context = this, username = user, password = pass, onSuccess = { token -> // Nach erfolgreichem Login: einmalig komplette DB ziehen DatabaseDownloader.downloadAndReplaceDatabase( context = this, token = token ) { ok -> showBusy(false) // Wenn Download fehlgeschlagen ist, aber evtl. schon eine DB lokal liegt, // lassen wir den Nutzer trotzdem weiterarbeiten (Offline). if (!ok && !hasLocalDb()) { Toast.makeText(this, "Download fehlgeschlagen – keine lokale Datenbank vorhanden", Toast.LENGTH_LONG).show() // Zurück zum Login, damit man es erneut probieren kann showLoginThenDownload() return@downloadAndReplaceDatabase } if (!ok) { Toast.makeText(this, "Download fehlgeschlagen – arbeite offline mit vorhandener DB", Toast.LENGTH_LONG).show() } // Opening-Screen starten openingScreenHandler = HandlerOpeningScreen(this) openingScreenHandler.init() openingScreenHandler.refreshHeaderStatusLive() } }, onError = { msg -> showBusy(false) Toast.makeText(this, msg, Toast.LENGTH_LONG).show() showLoginThenDownload() } ) } .setNegativeButton("Beenden") { _, _ -> finishAffinity() } .create() dialog.show() } private fun showBusy(show: Boolean) { if (show) { if (progress == null) { progress = ProgressBar(this).apply { isIndeterminate = true (window?.decorView as? android.view.ViewGroup)?.addView(this) } } progress?.visibility = View.VISIBLE } else { progress?.visibility = View.GONE } } private fun dp(v: Int): Int = (v * resources.displayMetrics.density).toInt() // --- LIVE NETZSTATUS (optional, für deine Status-Leiste) --- override fun onResume() { super.onResume() registerNetworkCallback() if (::openingScreenHandler.isInitialized && !isInQuestionnaire) { openingScreenHandler.refreshHeaderStatusLive() } } override fun onPause() { super.onPause() unregisterNetworkCallback() } private fun registerNetworkCallback() { if (netCb != null) return val cm = getSystemService(ConnectivityManager::class.java) val req = NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build() netCb = object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: Network) { runOnUiThread { if (::openingScreenHandler.isInitialized && !isInQuestionnaire) { openingScreenHandler.refreshHeaderStatusLive() } } } override fun onLost(network: Network) { runOnUiThread { if (::openingScreenHandler.isInitialized && !isInQuestionnaire) { openingScreenHandler.refreshHeaderStatusLive() } } } override fun onCapabilitiesChanged(network: Network, caps: NetworkCapabilities) { runOnUiThread { if (::openingScreenHandler.isInitialized && !isInQuestionnaire) { openingScreenHandler.refreshHeaderStatusLive() } } } } cm.registerNetworkCallback(req, netCb!!) } private fun unregisterNetworkCallback() { val cb = netCb ?: return val cm = getSystemService(ConnectivityManager::class.java) cm.unregisterNetworkCallback(cb) netCb = null } // --- /LIVE NETZSTATUS --- override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) } fun startQuestionnaire(questionnaire: QuestionnaireBase<*>, languageID: String) { isInQuestionnaire = true isFirstQuestionnairePage = true questionnaire.attach(this, languageID) questionnaire.startQuestionnaire() } override fun onBackPressed() { if (!::openingScreenHandler.isInitialized || !openingScreenHandler.onBackPressed()) { super.onBackPressed() } } fun finishQuestionnaire() { isInQuestionnaire = false isFirstQuestionnairePage = false if (::openingScreenHandler.isInitialized) { openingScreenHandler.init() } } }