removed error: Toast.makeText(activity, "Fehlende View: $name", Toast.LENGTH_LONG).show()

This commit is contained in:
oxidiert
2025-09-18 08:50:59 +02:00
parent 4cf840b37a
commit 7014386953
2 changed files with 21 additions and 28 deletions

View File

@ -17,7 +17,6 @@ import org.json.JSONArray
import java.io.File
import java.nio.charset.Charset
import kotlin.math.roundToInt
import org.apache.poi.ss.usermodel.Row
import org.apache.poi.xssf.usermodel.XSSFWorkbook
@ -89,7 +88,7 @@ class DatabaseButtonHandler(
uiScope.launch {
try {
progress.visibility = View.VISIBLE
val savedUri = exportHeadersForAllClients() // => speichert NUR in Downloads
val savedUri = exportHeadersForAllClients() // -> speichert NUR in Downloads
progress.visibility = View.GONE
if (savedUri != null) {
@ -101,10 +100,6 @@ class DatabaseButtonHandler(
} else {
Toast.makeText(activity, "Export fehlgeschlagen.", Toast.LENGTH_LONG).show()
}
} catch (e: SecurityException) {
progress.visibility = View.GONE
Log.e(tag, "Berechtigungsfehler beim Schreiben nach Downloads: ${e.message}", e)
Toast.makeText(activity, "Fehlende Speicherberechtigung (ältere Android-Version).", Toast.LENGTH_LONG).show()
} catch (e: Exception) {
progress.visibility = View.GONE
Log.e(tag, "Download Header Fehler: ${e.message}", e)
@ -114,13 +109,11 @@ class DatabaseButtonHandler(
}
/**
* Erzeugt eine Excel-Datei (ClientHeaders.xlsx) und speichert sie AUSSCHLIESSLICH
* im öffentlichen Geräte-Ordner „Downloads“.
*
* Hinweis zu alten Geräten (Android 9 und älter):
* - Füge ggf. in der AndroidManifest.xml hinzu:
* <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
* und frage die Laufzeitberechtigung ab, falls dein targetSdk das erfordert.
* Erzeugt eine Excel-Datei (ClientHeaders.xlsx) mit:
* - Zeile 1: Spalten-IDs (header_order.json / header_order.xlsx)
* - Zeile 2: ENGLISCHE Fragen/Beschriftungen zu jeder ID (rein EN, keine IDs mehr)
* - Ab Zeile 3: pro Client die Werte ("Done"/"Not Done"/Antwort oder "None")
* - Speichert AUSSCHLIESSLICH in den öffentlichen Geräte-Ordner "Downloads"
*/
private suspend fun exportHeadersForAllClients(): Uri? {
val orderedIds = loadOrderedIds()
@ -168,7 +161,7 @@ class DatabaseButtonHandler(
id in questionnaireIdSet -> if (statusMap[id] == true) "Done" else "Not Done"
else -> answerMap[id]?.takeIf { it.isNotBlank() } ?: "None"
}
val out = localizeForExportEn(id, raw) // Export immer EN (Done/Not Done/None bleiben)
val out = localizeForExportEn(id, raw) // Export immer EN
row.createCell(c++).setCellValue(out)
}
}
@ -179,38 +172,39 @@ class DatabaseButtonHandler(
}
wb.close()
// NUR Downloads speichern
val uri = saveToDownloads(
// -> nur in Downloads speichern (Q+ via MediaStore, sonst Public Downloads)
return saveToDownloads(
filename = "ClientHeaders.xlsx",
mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
bytes = bytes
)
return uri
}
// Speichert Bytes nach Downloads“ (Android 10+ via MediaStore, sonst klassisch).
/** Speichert Bytes nach "Downloads". */
private fun saveToDownloads(filename: String, mimeType: String, bytes: ByteArray): Uri? {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// Android 10+ (Scoped Storage)
val resolver = activity.contentResolver
val values = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
put(MediaStore.MediaColumns.MIME_TYPE, mimeType)
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
// optional: put(MediaStore.MediaColumns.IS_PENDING, 1)
}
val collection = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
val uri = resolver.insert(collection, values)
if (uri != null) {
resolver.openOutputStream(uri)?.use { it.write(bytes) } ?: return null
// optional: values.clear(); values.put(MediaStore.MediaColumns.IS_PENDING, 0); resolver.update(uri, values, null, null)
uri
} else null
} else {
// Android 9 (API 28) und älter: öffentliches Downloads-Verzeichnis
// Android 9 und älter public Downloads (WRITE_EXTERNAL_STORAGE kann nötig sein)
val downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
if (!downloadsDir.exists()) downloadsDir.mkdirs()
val outFile = File(downloadsDir, filename)
outFile.writeBytes(bytes)
// Im System sichtbar machen
// im System sichtbar machen
MediaScannerConnection.scanFile(
activity,
arrayOf(outFile.absolutePath),
@ -261,7 +255,7 @@ class DatabaseButtonHandler(
private fun openClientOverviewScreen(clientCode: String) {
activity.setContentView(R.layout.client_overview_screen)
val title: TextView = requireView(R.id.titleQuestionnaireDetail, "titleQuestionnaireDetail")
val title: TextView = requireView(R.id.titleClientOverview, "titleClientOverview")
val tableQ: TableLayout = requireView(R.id.tableQuestionnaires, "tableQuestionnaires")
val progress: ProgressBar = requireView(R.id.progressBarClient, "progressBarClient")
val emptyView: TextView = requireView(R.id.emptyViewClient, "emptyViewClient")
@ -534,10 +528,9 @@ class DatabaseButtonHandler(
private fun localizeEnglishNoBrackets(key: String): String? {
val t = try { LanguageManager.getText("ENGLISH", key) } catch (_: Exception) { null }
if (t == null) return null
val m = Regex("^\\[(.*)]$").matchEntire(t.trim())
val m = Regex("^\\[(.*)]$").matchEntire(t?.trim() ?: "")
val stripped = m?.groupValues?.get(1) ?: t
if (stripped.isBlank() || stripped.equals(key, ignoreCase = true)) return null
if (stripped == null || stripped.isBlank() || stripped.equals(key, ignoreCase = true)) return null
return stripped
}
@ -593,7 +586,7 @@ class DatabaseButtonHandler(
val row = TableRow(activity).apply {
isClickable = true
isFocusable = true
setBackgroundResource(android.R.drawable.list_selector_background)
setBackgroundColor(android.graphics.Color.TRANSPARENT)
setOnClickListener { onClick() }
}
cells.forEachIndexed { index, text ->