saving header in downloads
This commit is contained in:
@ -1,6 +1,11 @@
|
||||
package com.dano.test1
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.media.MediaScannerConnection
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.*
|
||||
@ -84,18 +89,22 @@ class DatabaseButtonHandler(
|
||||
uiScope.launch {
|
||||
try {
|
||||
progress.visibility = View.VISIBLE
|
||||
val exportFile = exportHeadersForAllClients()
|
||||
val savedUri = exportHeadersForAllClients() // => speichert NUR in Downloads
|
||||
progress.visibility = View.GONE
|
||||
|
||||
if (exportFile != null) {
|
||||
if (savedUri != null) {
|
||||
Toast.makeText(
|
||||
activity,
|
||||
"Export erfolgreich: ${exportFile.absolutePath}",
|
||||
"Export erfolgreich: Downloads/ClientHeaders.xlsx",
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
} 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)
|
||||
@ -105,12 +114,15 @@ class DatabaseButtonHandler(
|
||||
}
|
||||
|
||||
/**
|
||||
* 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")
|
||||
* 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.
|
||||
*/
|
||||
private suspend fun exportHeadersForAllClients(): File? {
|
||||
private suspend fun exportHeadersForAllClients(): Uri? {
|
||||
val orderedIds = loadOrderedIds()
|
||||
if (orderedIds.isEmpty()) return null
|
||||
|
||||
@ -161,25 +173,52 @@ class DatabaseButtonHandler(
|
||||
}
|
||||
}
|
||||
|
||||
// Datei schreiben: extern + intern
|
||||
// Bytes erzeugen
|
||||
val bytes = java.io.ByteArrayOutputStream().use { bos ->
|
||||
wb.write(bos); bos.toByteArray()
|
||||
}
|
||||
wb.close()
|
||||
|
||||
val extDir = activity.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)?.apply { mkdirs() }
|
||||
val extFile = extDir?.let { File(it, "ClientHeaders.xlsx") }?.apply { writeBytes(bytes) }
|
||||
// NUR Downloads speichern
|
||||
val uri = saveToDownloads(
|
||||
filename = "ClientHeaders.xlsx",
|
||||
mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
bytes = bytes
|
||||
)
|
||||
|
||||
val intDir = File(activity.filesDir, "exports").apply { mkdirs() }
|
||||
val intFile = File(intDir, "ClientHeaders.xlsx").apply { writeBytes(bytes) }
|
||||
return uri
|
||||
}
|
||||
|
||||
Toast.makeText(
|
||||
activity,
|
||||
"Export:\n• intern: ${intFile.absolutePath}\n• extern: ${extFile?.absolutePath ?: "—"}",
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
|
||||
return extFile ?: intFile
|
||||
// Speichert Bytes nach „Downloads“ (Android 10+ via MediaStore, sonst klassisch).
|
||||
private fun saveToDownloads(filename: String, mimeType: String, bytes: ByteArray): Uri? {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
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)
|
||||
}
|
||||
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
|
||||
uri
|
||||
} else null
|
||||
} else {
|
||||
// Android 9 (API 28) und älter: öffentliches Downloads-Verzeichnis
|
||||
val downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
||||
if (!downloadsDir.exists()) downloadsDir.mkdirs()
|
||||
val outFile = File(downloadsDir, filename)
|
||||
outFile.writeBytes(bytes)
|
||||
// Im System sichtbar machen
|
||||
MediaScannerConnection.scanFile(
|
||||
activity,
|
||||
arrayOf(outFile.absolutePath),
|
||||
arrayOf(mimeType),
|
||||
null
|
||||
)
|
||||
Uri.fromFile(outFile)
|
||||
}
|
||||
}
|
||||
|
||||
// Liefert einen englischen, lesbaren Fragetext/Titel zu einer ID (nur EN, keine IDs).
|
||||
@ -222,7 +261,7 @@ class DatabaseButtonHandler(
|
||||
private fun openClientOverviewScreen(clientCode: String) {
|
||||
activity.setContentView(R.layout.client_overview_screen)
|
||||
|
||||
val title: TextView = requireView(R.id.titleClientOverview, "titleClientOverview")
|
||||
val title: TextView = requireView(R.id.titleQuestionnaireDetail, "titleQuestionnaireDetail")
|
||||
val tableQ: TableLayout = requireView(R.id.tableQuestionnaires, "tableQuestionnaires")
|
||||
val progress: ProgressBar = requireView(R.id.progressBarClient, "progressBarClient")
|
||||
val emptyView: TextView = requireView(R.id.emptyViewClient, "emptyViewClient")
|
||||
|
||||
Reference in New Issue
Block a user