removed error: Toast.makeText(activity, "Fehlende View: $name", Toast.LENGTH_LONG).show()
This commit is contained in:
4
.idea/deploymentTargetSelector.xml
generated
4
.idea/deploymentTargetSelector.xml
generated
@ -4,10 +4,10 @@
|
|||||||
<selectionStates>
|
<selectionStates>
|
||||||
<SelectionState runConfigName="app">
|
<SelectionState runConfigName="app">
|
||||||
<option name="selectionMode" value="DROPDOWN" />
|
<option name="selectionMode" value="DROPDOWN" />
|
||||||
<DropdownSelection timestamp="2025-09-06T18:16:00.187475900Z">
|
<DropdownSelection timestamp="2025-09-17T11:15:49.688310200Z">
|
||||||
<Target type="DEFAULT_BOOT">
|
<Target type="DEFAULT_BOOT">
|
||||||
<handle>
|
<handle>
|
||||||
<DeviceId pluginId="PhysicalDevice" identifier="serial=HA218GZY" />
|
<DeviceId pluginId="LocalEmulator" identifier="path=C:\Users\danie\.android\avd\Medium_Phone.avd" />
|
||||||
</handle>
|
</handle>
|
||||||
</Target>
|
</Target>
|
||||||
</DropdownSelection>
|
</DropdownSelection>
|
||||||
|
|||||||
@ -17,7 +17,6 @@ import org.json.JSONArray
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
import org.apache.poi.ss.usermodel.Row
|
import org.apache.poi.ss.usermodel.Row
|
||||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook
|
||||||
|
|
||||||
@ -89,7 +88,7 @@ class DatabaseButtonHandler(
|
|||||||
uiScope.launch {
|
uiScope.launch {
|
||||||
try {
|
try {
|
||||||
progress.visibility = View.VISIBLE
|
progress.visibility = View.VISIBLE
|
||||||
val savedUri = exportHeadersForAllClients() // => speichert NUR in Downloads
|
val savedUri = exportHeadersForAllClients() // -> speichert NUR in Downloads
|
||||||
progress.visibility = View.GONE
|
progress.visibility = View.GONE
|
||||||
|
|
||||||
if (savedUri != null) {
|
if (savedUri != null) {
|
||||||
@ -101,10 +100,6 @@ class DatabaseButtonHandler(
|
|||||||
} else {
|
} else {
|
||||||
Toast.makeText(activity, "Export fehlgeschlagen.", Toast.LENGTH_LONG).show()
|
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) {
|
} catch (e: Exception) {
|
||||||
progress.visibility = View.GONE
|
progress.visibility = View.GONE
|
||||||
Log.e(tag, "Download Header Fehler: ${e.message}", e)
|
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
|
* Erzeugt eine Excel-Datei (ClientHeaders.xlsx) mit:
|
||||||
* im öffentlichen Geräte-Ordner „Downloads“.
|
* - Zeile 1: Spalten-IDs (header_order.json / header_order.xlsx)
|
||||||
*
|
* - Zeile 2: ENGLISCHE Fragen/Beschriftungen zu jeder ID (rein EN, keine IDs mehr)
|
||||||
* Hinweis zu alten Geräten (Android 9 und älter):
|
* - Ab Zeile 3: pro Client die Werte ("Done"/"Not Done"/Antwort oder "None")
|
||||||
* - Füge ggf. in der AndroidManifest.xml hinzu:
|
* - Speichert AUSSCHLIESSLICH in den öffentlichen Geräte-Ordner "Downloads"
|
||||||
* <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
|
||||||
* und frage die Laufzeitberechtigung ab, falls dein targetSdk das erfordert.
|
|
||||||
*/
|
*/
|
||||||
private suspend fun exportHeadersForAllClients(): Uri? {
|
private suspend fun exportHeadersForAllClients(): Uri? {
|
||||||
val orderedIds = loadOrderedIds()
|
val orderedIds = loadOrderedIds()
|
||||||
@ -168,7 +161,7 @@ class DatabaseButtonHandler(
|
|||||||
id in questionnaireIdSet -> if (statusMap[id] == true) "Done" else "Not Done"
|
id in questionnaireIdSet -> if (statusMap[id] == true) "Done" else "Not Done"
|
||||||
else -> answerMap[id]?.takeIf { it.isNotBlank() } ?: "None"
|
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)
|
row.createCell(c++).setCellValue(out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,38 +172,39 @@ class DatabaseButtonHandler(
|
|||||||
}
|
}
|
||||||
wb.close()
|
wb.close()
|
||||||
|
|
||||||
// NUR Downloads speichern
|
// -> nur in Downloads speichern (Q+ via MediaStore, sonst Public Downloads)
|
||||||
val uri = saveToDownloads(
|
return saveToDownloads(
|
||||||
filename = "ClientHeaders.xlsx",
|
filename = "ClientHeaders.xlsx",
|
||||||
mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
bytes = bytes
|
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? {
|
private fun saveToDownloads(filename: String, mimeType: String, bytes: ByteArray): Uri? {
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
// Android 10+ (Scoped Storage)
|
||||||
val resolver = activity.contentResolver
|
val resolver = activity.contentResolver
|
||||||
val values = ContentValues().apply {
|
val values = ContentValues().apply {
|
||||||
put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
|
put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
|
||||||
put(MediaStore.MediaColumns.MIME_TYPE, mimeType)
|
put(MediaStore.MediaColumns.MIME_TYPE, mimeType)
|
||||||
put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
|
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 collection = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
|
||||||
val uri = resolver.insert(collection, values)
|
val uri = resolver.insert(collection, values)
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
resolver.openOutputStream(uri)?.use { it.write(bytes) } ?: return 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
|
uri
|
||||||
} else null
|
} else null
|
||||||
} else {
|
} 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)
|
val downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
||||||
if (!downloadsDir.exists()) downloadsDir.mkdirs()
|
if (!downloadsDir.exists()) downloadsDir.mkdirs()
|
||||||
val outFile = File(downloadsDir, filename)
|
val outFile = File(downloadsDir, filename)
|
||||||
outFile.writeBytes(bytes)
|
outFile.writeBytes(bytes)
|
||||||
// Im System sichtbar machen
|
// im System sichtbar machen
|
||||||
MediaScannerConnection.scanFile(
|
MediaScannerConnection.scanFile(
|
||||||
activity,
|
activity,
|
||||||
arrayOf(outFile.absolutePath),
|
arrayOf(outFile.absolutePath),
|
||||||
@ -261,7 +255,7 @@ class DatabaseButtonHandler(
|
|||||||
private fun openClientOverviewScreen(clientCode: String) {
|
private fun openClientOverviewScreen(clientCode: String) {
|
||||||
activity.setContentView(R.layout.client_overview_screen)
|
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 tableQ: TableLayout = requireView(R.id.tableQuestionnaires, "tableQuestionnaires")
|
||||||
val progress: ProgressBar = requireView(R.id.progressBarClient, "progressBarClient")
|
val progress: ProgressBar = requireView(R.id.progressBarClient, "progressBarClient")
|
||||||
val emptyView: TextView = requireView(R.id.emptyViewClient, "emptyViewClient")
|
val emptyView: TextView = requireView(R.id.emptyViewClient, "emptyViewClient")
|
||||||
@ -534,10 +528,9 @@ class DatabaseButtonHandler(
|
|||||||
|
|
||||||
private fun localizeEnglishNoBrackets(key: String): String? {
|
private fun localizeEnglishNoBrackets(key: String): String? {
|
||||||
val t = try { LanguageManager.getText("ENGLISH", key) } catch (_: Exception) { null }
|
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
|
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
|
return stripped
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -593,7 +586,7 @@ class DatabaseButtonHandler(
|
|||||||
val row = TableRow(activity).apply {
|
val row = TableRow(activity).apply {
|
||||||
isClickable = true
|
isClickable = true
|
||||||
isFocusable = true
|
isFocusable = true
|
||||||
setBackgroundResource(android.R.drawable.list_selector_background)
|
setBackgroundColor(android.graphics.Color.TRANSPARENT)
|
||||||
setOnClickListener { onClick() }
|
setOnClickListener { onClick() }
|
||||||
}
|
}
|
||||||
cells.forEachIndexed { index, text ->
|
cells.forEachIndexed { index, text ->
|
||||||
|
|||||||
Reference in New Issue
Block a user