Big commit.

Managed to do upload and download right. No Race conditions.
This commit is contained in:
oxidiert
2025-08-15 10:11:32 +02:00
parent a0c906b754
commit e6c2526529
5 changed files with 71 additions and 8 deletions

View File

@ -11,7 +11,8 @@ import androidx.room.RoomDatabase
Answer::class,
CompletedQuestionnaire::class
],
version = 10
version = 1,
exportSchema = false
)
abstract class AppDatabase : RoomDatabase() {
abstract fun clientDao(): ClientDao
@ -20,3 +21,4 @@ abstract class AppDatabase : RoomDatabase() {
abstract fun answerDao(): AnswerDao
abstract fun completedQuestionnaireDao(): CompletedQuestionnaireDao
}

View File

@ -12,8 +12,15 @@ interface ClientDao {
@Delete
suspend fun deleteClient(client: Client)
@Query("SELECT COUNT(*) FROM clients")
suspend fun getClientCount(): Int
@Query("SELECT * FROM clients")
suspend fun getAllClients(): List<Client>
}
@Dao
interface QuestionnaireDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)

View File

@ -18,7 +18,8 @@ import kotlin.system.exitProcess
object DatabaseUploader {
private const val DB_NAME = "questionnaire_database"
private const val SERVER_DELTA_URL = "http://49.13.157.44/uploadDelta.php"
// TODO entferne uploadDeltaTest.php
private const val SERVER_DELTA_URL = "http://49.13.157.44/uploadDeltaTest.php"
private const val SERVER_CHECK_URL = "http://49.13.157.44/checkDatabaseExists.php"
private const val API_TOKEN = "MEIN_SUPER_GEHEIMES_TOKEN_12345"
@ -56,10 +57,10 @@ object DatabaseUploader {
val exists = checkDatabaseExists()
if (exists) {
Log.d("UPLOAD", "Server-Datenbank vorhanden → Delta-Upload")
uploadDelta(dbFile)
uploadPseudoDelta(dbFile)
} else {
Log.d("UPLOAD", "Keine Server-Datenbank → Delta-Upload")
uploadDelta(dbFile)
uploadPseudoDelta(dbFile)
}
} catch (e: Exception) {
@ -94,7 +95,7 @@ object DatabaseUploader {
}
}
private fun uploadDelta(file: File) {
private fun uploadPseudoDelta(file: File) {
try {
val db = SQLiteDatabase.openDatabase(file.absolutePath, null, SQLiteDatabase.OPEN_READONLY)
@ -138,12 +139,18 @@ object DatabaseUploader {
}
if (response.isSuccessful) {
Log.d("UPLOAD", "Delta-Upload erfolgreich: $body")
// Lösche Hauptdatenbank
if (file.delete()) {
Log.d("UPLOAD", "Lokale DB gelöscht.")
exitProcess(0)
} else {
Log.e("UPLOAD", "Löschen der lokalen DB fehlgeschlagen.")
}
// Lösche Journal-Datei
val journalFile = File(file.parent, file.name + "-journal")
if (journalFile.exists() && journalFile.delete()) {
Log.d("UPLOAD", "Journal-Datei gelöscht.")
}
exitProcess(0)
} else {
Log.e("UPLOAD", "Delta-Upload fehlgeschlagen: ${response.code} $body")
}

View File

@ -9,6 +9,7 @@ import android.widget.*
import kotlinx.coroutines.*
import org.json.JSONArray
import android.util.Log
import java.io.File
var INTEGRATION_INDEX_POINTS: Int? = null
@ -35,6 +36,7 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
activity.setContentView(R.layout.opening_screen)
bindViews()
loadQuestionnaireOrder()
createQuestionnaireButtons()
restorePreviousClientCode()
@ -46,11 +48,22 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
setupUploadButton()
setupDownloadButton()
val dbPath = "/data/data/com.dano.test1/databases/questionnaire_database"
val pathExists = File(dbPath).exists()
if (pathExists) {
updateMainButtonsState(true)
}
else{
updateMainButtonsState(false)
}
if (!editText.text.isNullOrBlank()) {
buttonLoad.performClick()
}
}
private fun bindViews() {
editText = activity.findViewById(R.id.editText)
spinner = activity.findViewById(R.id.string_spinner1)
@ -183,13 +196,12 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
}
withContext(Dispatchers.Main) {
updateMainButtonsState(true) // Datenbank vorhanden -> Buttons aktivieren
handleNormalLoad(clientCode)
}
}
}
private suspend fun handleNormalLoad(clientCode: String) {
val completedIds = withContext(Dispatchers.IO) {
MyApp.database.completedQuestionnaireDao().getCompletedQuestionnairesForClient(clientCode)
@ -559,6 +571,22 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
}
}
// --- Füge diese Funktion in deine Klasse ein ---
private fun isDatabasePopulated(): Boolean {
return try {
// Wir prüfen, ob die Datenbank mindestens eine nicht-interne Tabelle enthält.
// Das ist robust gegenüber verschiedenen Tabellennamen.
val db = MyApp.database.openHelper.readableDatabase
val cursor = db.query(
"SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name != 'room_master_table'"
)
cursor.use { it.count > 0 }
} catch (e: Exception) {
// Falls etwas schiefgeht (z.B. DB noch nicht vorhanden), gilt: nicht vorhanden
false
}
}
private fun setupDownloadButton() {
downloadButton.text = "Download"
downloadButton.setOnClickListener {
@ -568,7 +596,15 @@ class HandlerOpeningScreen(private val activity: MainActivity) {
Toast.makeText(activity, "Datenbank wird heruntergeladen...", Toast.LENGTH_SHORT).show()
DatabaseDownloader.downloadAndReplaceDatabase(activity)
updateMainButtonsState(true)
}
}
private fun updateMainButtonsState(isDatabaseAvailable: Boolean) {
val buttons = listOf(buttonLoad, saveButton, editButton)
buttons.forEach { button ->
button.isEnabled = isDatabaseAvailable
button.alpha = if (isDatabaseAvailable) 1.0f else 0.5f
}
}
}

View File

@ -1,7 +1,9 @@
package com.dano.test1
import android.app.Application
import android.util.Log
import androidx.room.Room
import androidx.room.RoomDatabase
import com.dano.test1.data.AppDatabase
class MyApp : Application() {
@ -13,12 +15,21 @@ class MyApp : Application() {
override fun onCreate() {
super.onCreate()
// Room Datenbank bauen: nur die Hauptdatei, ohne WAL und Journal
database = Room.databaseBuilder(
applicationContext,
AppDatabase::class.java,
"questionnaire_database"
)
.fallbackToDestructiveMigration()
.setJournalMode(RoomDatabase.JournalMode.TRUNCATE) // TRUNCATE = keine -wal Datei, nur Hauptdatei
.addCallback(object : RoomDatabase.Callback() {
override fun onOpen(db: androidx.sqlite.db.SupportSQLiteDatabase) {
super.onOpen(db)
Log.d("DB", "Datenbank geöffnet. Nur questionnaire_database wird genutzt.")
}
})
.build()
}
}