Export SQLite database
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
package de.markusfisch.android.binaryeye.data
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import de.markusfisch.android.binaryeye.app.writeExternalFile
|
||||
|
||||
fun exportCsv(
|
||||
context: Context,
|
||||
name: String,
|
||||
cursor: Cursor,
|
||||
delimiter: String
|
||||
) {
|
||||
if (!cursor.moveToFirst()) {
|
||||
return
|
||||
}
|
||||
val columns = arrayOf(
|
||||
Database.SCANS_DATETIME,
|
||||
Database.SCANS_FORMAT,
|
||||
Database.SCANS_CONTENT,
|
||||
Database.SCANS_ERROR_CORRECTION_LEVEL,
|
||||
Database.SCANS_ISSUE_NUMBER,
|
||||
Database.SCANS_ORIENTATION,
|
||||
Database.SCANS_OTHER_META_DATA,
|
||||
Database.SCANS_PDF417_EXTRA_METADATA,
|
||||
Database.SCANS_POSSIBLE_COUNTRY,
|
||||
Database.SCANS_SUGGESTED_PRICE,
|
||||
Database.SCANS_UPC_EAN_EXTENSION
|
||||
)
|
||||
val indices = columns.map {
|
||||
cursor.getColumnIndex(it)
|
||||
}
|
||||
val contentIndex = cursor.getColumnIndex(Database.SCANS_CONTENT)
|
||||
val rawIndex = cursor.getColumnIndex(Database.SCANS_RAW)
|
||||
writeExternalFile(context, name, "text/csv") { outputStream ->
|
||||
outputStream.write(
|
||||
columns.joinToString(
|
||||
delimiter,
|
||||
postfix = "\n"
|
||||
).toByteArray()
|
||||
)
|
||||
do {
|
||||
var deviation: Pair<Int, String>? = null
|
||||
if (cursor.getString(contentIndex)?.isEmpty() == true) {
|
||||
deviation = Pair(
|
||||
contentIndex,
|
||||
cursor.getBlob(rawIndex).toHexString()
|
||||
)
|
||||
}
|
||||
outputStream.write(
|
||||
cursor.toCsvRecord(indices, delimiter, deviation)
|
||||
)
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
}
|
||||
|
||||
private fun ByteArray.toHexString(): String {
|
||||
val hex = StringBuilder()
|
||||
for (i in this.indices) {
|
||||
hex.append(String.format("%02X", this[i]))
|
||||
}
|
||||
return hex.toString()
|
||||
}
|
||||
|
||||
private fun Cursor.toCsvRecord(
|
||||
indices: List<Int>,
|
||||
delimiter: String,
|
||||
deviation: Pair<Int, String>?
|
||||
): ByteArray {
|
||||
val sb = StringBuilder()
|
||||
indices.forEach {
|
||||
val value = if (deviation?.first == it) {
|
||||
deviation.second
|
||||
} else {
|
||||
this.getString(it)
|
||||
}
|
||||
sb.append(value?.quoteAndEscape() ?: "")
|
||||
sb.append(delimiter)
|
||||
}
|
||||
sb.append("\n")
|
||||
return sb.toString().toByteArray()
|
||||
}
|
||||
|
||||
private fun String.quoteAndEscape() = "\"${this
|
||||
.replace("\n", " ")
|
||||
.replace("\"", "\"\"")}\""
|
||||
@@ -184,7 +184,7 @@ class Database {
|
||||
}
|
||||
|
||||
private class OpenHelper(context: Context) :
|
||||
SQLiteOpenHelper(context, "history.db", null, 4) {
|
||||
SQLiteOpenHelper(context, FILE_NAME, null, 4) {
|
||||
override fun onCreate(db: SQLiteDatabase) {
|
||||
createScans(db)
|
||||
}
|
||||
@@ -207,6 +207,7 @@ class Database {
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val FILE_NAME = "history.db"
|
||||
const val SCANS = "scans"
|
||||
const val SCANS_ID = "_id"
|
||||
const val SCANS_DATETIME = "_datetime"
|
||||
|
||||
@@ -1,85 +1,39 @@
|
||||
package de.markusfisch.android.binaryeye.data
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.app.Activity
|
||||
import android.os.Environment
|
||||
import de.markusfisch.android.binaryeye.R
|
||||
import de.markusfisch.android.binaryeye.app.hasWritePermission
|
||||
import de.markusfisch.android.binaryeye.app.writeExternalFile
|
||||
import de.markusfisch.android.binaryeye.widget.toast
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
|
||||
fun exportCsv(
|
||||
context: Context,
|
||||
name: String,
|
||||
cursor: Cursor,
|
||||
delimiter: String
|
||||
) {
|
||||
if (!cursor.moveToFirst()) {
|
||||
fun exportDatabase(activity: Activity, fileName: String) {
|
||||
if (!hasWritePermission(activity)) {
|
||||
return
|
||||
}
|
||||
val columns = arrayOf(
|
||||
Database.SCANS_DATETIME,
|
||||
Database.SCANS_FORMAT,
|
||||
Database.SCANS_CONTENT,
|
||||
Database.SCANS_ERROR_CORRECTION_LEVEL,
|
||||
Database.SCANS_ISSUE_NUMBER,
|
||||
Database.SCANS_ORIENTATION,
|
||||
Database.SCANS_OTHER_META_DATA,
|
||||
Database.SCANS_PDF417_EXTRA_METADATA,
|
||||
Database.SCANS_POSSIBLE_COUNTRY,
|
||||
Database.SCANS_SUGGESTED_PRICE,
|
||||
Database.SCANS_UPC_EAN_EXTENSION
|
||||
val dbFile = File(
|
||||
Environment.getDataDirectory(),
|
||||
"//data//${activity.packageName}//databases//${Database.FILE_NAME}"
|
||||
)
|
||||
val indices = columns.map {
|
||||
cursor.getColumnIndex(it)
|
||||
if (!dbFile.exists()) {
|
||||
activity.toast(R.string.error_no_content)
|
||||
return
|
||||
}
|
||||
val contentIndex = cursor.getColumnIndex(Database.SCANS_CONTENT)
|
||||
val rawIndex = cursor.getColumnIndex(Database.SCANS_RAW)
|
||||
writeExternalFile(context, name, "text/csv") { outputStream ->
|
||||
outputStream.write(
|
||||
columns.joinToString(
|
||||
delimiter,
|
||||
postfix = "\n"
|
||||
).toByteArray()
|
||||
)
|
||||
do {
|
||||
var deviation: Pair<Int, String>? = null
|
||||
if (cursor.getString(contentIndex)?.isEmpty() == true) {
|
||||
deviation = Pair(
|
||||
contentIndex,
|
||||
cursor.getBlob(rawIndex).toHexString()
|
||||
)
|
||||
}
|
||||
outputStream.write(
|
||||
cursor.toCsvRecord(indices, delimiter, deviation)
|
||||
)
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
}
|
||||
|
||||
private fun ByteArray.toHexString(): String {
|
||||
val hex = StringBuilder()
|
||||
for (i in this.indices) {
|
||||
hex.append(String.format("%02X", this[i]))
|
||||
}
|
||||
return hex.toString()
|
||||
}
|
||||
|
||||
private fun Cursor.toCsvRecord(
|
||||
indices: List<Int>,
|
||||
delimiter: String,
|
||||
deviation: Pair<Int, String>?
|
||||
): ByteArray {
|
||||
val sb = StringBuilder()
|
||||
indices.forEach {
|
||||
val value = if (deviation?.first == it) {
|
||||
deviation.second
|
||||
} else {
|
||||
this.getString(it)
|
||||
GlobalScope.launch {
|
||||
val message = writeExternalFile(
|
||||
activity,
|
||||
fileName,
|
||||
"application/vnd.sqlite3"
|
||||
) {
|
||||
FileInputStream(dbFile).copyTo(it)
|
||||
}
|
||||
GlobalScope.launch(Main) {
|
||||
activity.toast(message)
|
||||
}
|
||||
sb.append(value?.quoteAndEscape() ?: "")
|
||||
sb.append(delimiter)
|
||||
}
|
||||
sb.append("\n")
|
||||
return sb.toString().toByteArray()
|
||||
}
|
||||
|
||||
private fun String.quoteAndEscape() = "\"${this
|
||||
.replace("\n", " ")
|
||||
.replace("\"", "\"\"")}\""
|
||||
|
||||
@@ -23,6 +23,7 @@ import de.markusfisch.android.binaryeye.adapter.ScansAdapter
|
||||
import de.markusfisch.android.binaryeye.app.*
|
||||
import de.markusfisch.android.binaryeye.data.Database
|
||||
import de.markusfisch.android.binaryeye.data.exportCsv
|
||||
import de.markusfisch.android.binaryeye.data.exportDatabase
|
||||
import de.markusfisch.android.binaryeye.view.setPadding
|
||||
import de.markusfisch.android.binaryeye.view.setWindowInsetListener
|
||||
import de.markusfisch.android.binaryeye.view.useVisibility
|
||||
@@ -333,24 +334,30 @@ class HistoryFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun askToExportToFile(context: Context) = scope.launch {
|
||||
val ac = activity ?: return@launch
|
||||
progressView.useVisibility {
|
||||
if (!hasWritePermission(activity)) {
|
||||
if (!hasWritePermission(ac)) {
|
||||
return@useVisibility
|
||||
}
|
||||
val delimiters = context.resources.getStringArray(
|
||||
R.array.csv_delimiters_values
|
||||
val options = context.resources.getStringArray(
|
||||
R.array.export_options_values
|
||||
)
|
||||
val delimiter = alertDialog<String>(context) { resume ->
|
||||
setTitle(R.string.csv_delimiter)
|
||||
setItems(R.array.csv_delimiters_names) { _, which ->
|
||||
resume(delimiters[which])
|
||||
setTitle(R.string.export_as)
|
||||
setItems(R.array.export_options_names) { _, which ->
|
||||
resume(options[which])
|
||||
}
|
||||
} ?: return@useVisibility
|
||||
val isCsv = delimiter != "sql"
|
||||
val name = withContext(Dispatchers.Main) {
|
||||
activity.askForFileName(suffix = ".csv")
|
||||
ac.askForFileName(if (isCsv) ".csv" else ".db")
|
||||
} ?: return@useVisibility
|
||||
db.getScansDetailed(filter)?.use { cursor ->
|
||||
exportCsv(context, name, cursor, delimiter)
|
||||
if (isCsv) {
|
||||
db.getScansDetailed(filter)?.use { cursor ->
|
||||
exportCsv(context, name, cursor, delimiter)
|
||||
}
|
||||
} else {
|
||||
exportDatabase(ac, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
android:icon="@drawable/ic_action_search"
|
||||
android:title="@string/search_scan"
|
||||
material:actionViewClass="android.support.v7.widget.SearchView"
|
||||
material:showAsAction="collapseActionView|ifRoom"/>
|
||||
material:showAsAction="collapseActionView|always"/>
|
||||
<item
|
||||
android:id="@+id/export_history"
|
||||
android:icon="@drawable/ic_action_export"
|
||||
|
||||
@@ -79,9 +79,10 @@
|
||||
<string name="search_web">Suche im Internet</string>
|
||||
<string name="search_scan">Code suchen</string>
|
||||
<string name="export_to_file">In Datei exportieren</string>
|
||||
<string name="csv_delimiter">Welches Trennzeichen soll genutzt werden (CSV-Datei)?</string>
|
||||
<string name="delimiter_comma">Komma</string>
|
||||
<string name="delimiter_semicolon">Semikolon</string>
|
||||
<string name="export_as">Exportieren als?</string>
|
||||
<string name="export_csv_comma">CSV mit Kommas</string>
|
||||
<string name="export_csv_semicolon">CSV mit Semikolons</string>
|
||||
<string name="export_database">SQLite Datenbank exportieren</string>
|
||||
<string name="saved_in_downloads">In den Downloads gespeichert</string>
|
||||
<string name="rotate_image_cw">Bild im Uhrzeigersinn rotieren</string>
|
||||
<string name="pick_file">Bilddatei auswählen</string>
|
||||
|
||||
@@ -79,9 +79,10 @@
|
||||
<string name="search_web">Search the web</string>
|
||||
<string name="search_scan">Search scan</string>
|
||||
<string name="export_to_file">Export to file</string>
|
||||
<string name="csv_delimiter">Which delimiter should be used (CSV-File)?</string>
|
||||
<string name="delimiter_comma">Comma</string>
|
||||
<string name="delimiter_semicolon">Semicolon</string>
|
||||
<string name="export_as">Export as?</string>
|
||||
<string name="export_csv_comma">CSV with commas</string>
|
||||
<string name="export_csv_semicolon">CSV with semicolons</string>
|
||||
<string name="export_database">Export SQLite database</string>
|
||||
<string name="saved_in_downloads">Saved in downloads</string>
|
||||
<string name="rotate_image_cw">Rotate image clockwise</string>
|
||||
<string name="pick_file">Pick image file</string>
|
||||
|
||||
@@ -79,9 +79,10 @@
|
||||
<string name="search_web">Keresés a weben</string>
|
||||
<string name="search_scan">Search scan</string>
|
||||
<string name="export_to_file">Exportálás fájlba</string>
|
||||
<string name="csv_delimiter">Milyen mezőelválasztót kell használni (CSV-fájl)?</string>
|
||||
<string name="delimiter_comma">Vessző</string>
|
||||
<string name="delimiter_semicolon">Pontosvessző</string>
|
||||
<string name="export_as">Export as?</string>
|
||||
<string name="export_csv_comma">CSV with commas</string>
|
||||
<string name="export_csv_semicolon">CSV with semicolons</string>
|
||||
<string name="export_database">Export SQLite database</string>
|
||||
<string name="saved_in_downloads">Elmentve a letöltésekbe</string>
|
||||
<string name="rotate_image_cw">Kép forgatása jobbra</string>
|
||||
<string name="pick_file">Képfájl kiválasztása</string>
|
||||
|
||||
@@ -78,9 +78,10 @@
|
||||
<string name="search_web">Cari secara daring</string>
|
||||
<string name="search_scan">Cari pindaian</string>
|
||||
<string name="export_to_file">Ekspor ke berkas</string>
|
||||
<string name="csv_delimiter">Karakter pemisah apa yang harus digunakan (Berkas-CSV)?</string>
|
||||
<string name="delimiter_comma">Koma</string>
|
||||
<string name="delimiter_semicolon">Titik koma</string>
|
||||
<string name="export_as">Export as?</string>
|
||||
<string name="export_csv_comma">CSV with commas</string>
|
||||
<string name="export_csv_semicolon">CSV with semicolons</string>
|
||||
<string name="export_database">Export SQLite database</string>
|
||||
<string name="saved_in_downloads">Simpan di dalam unduhan</string>
|
||||
<string name="rotate_image_cw">Putar gambar searah jarum jam</string>
|
||||
<string name="pick_file">Pilih berkas gambar</string>
|
||||
|
||||
@@ -79,9 +79,10 @@
|
||||
<string name="search_web">Cerca nel web</string>
|
||||
<string name="search_scan">Search scan</string>
|
||||
<string name="export_to_file">Esporta su file</string>
|
||||
<string name="csv_delimiter">Quale delimitatore usare (File-CSV)?</string>
|
||||
<string name="delimiter_comma">Virgola</string>
|
||||
<string name="delimiter_semicolon">Punto e virgola</string>
|
||||
<string name="export_as">Export as?</string>
|
||||
<string name="export_csv_comma">CSV with commas</string>
|
||||
<string name="export_csv_semicolon">CSV with semicolons</string>
|
||||
<string name="export_database">Export SQLite database</string>
|
||||
<string name="saved_in_downloads">Salvato nei download</string>
|
||||
<string name="rotate_image_cw">Ruota immagine in senso orario</string>
|
||||
<string name="pick_file">Scegli file immagine</string>
|
||||
|
||||
@@ -75,9 +75,10 @@
|
||||
<string name="search_web">Het net doorzoeken</string>
|
||||
<string name="search_scan">Search scan</string>
|
||||
<string name="export_to_file">Naar bestand exporteren</string>
|
||||
<string name="csv_delimiter">Wat voor separator wil je gebruiken (CSV-bestand)?</string>
|
||||
<string name="delimiter_comma">Komma</string>
|
||||
<string name="delimiter_semicolon">Kommapunt</string>
|
||||
<string name="export_as">Export as?</string>
|
||||
<string name="export_csv_comma">CSV with commas</string>
|
||||
<string name="export_csv_semicolon">CSV with semicolons</string>
|
||||
<string name="export_database">Export SQLite database</string>
|
||||
<string name="error_saving_binary_data">Kon bestand niet opslaan</string>
|
||||
<string name="open_with_url">Niet herkende data met URL openen</string>
|
||||
<string name="pick_list_separator">Hoe de lijstonderdelen te separeren?</string>
|
||||
|
||||
@@ -79,9 +79,10 @@
|
||||
<string name="search_web">Search the web</string>
|
||||
<string name="search_scan">Search scan</string>
|
||||
<string name="export_to_file">Export to file</string>
|
||||
<string name="csv_delimiter">Which delimiter should be used (CSV-File)?</string>
|
||||
<string name="delimiter_comma">Comma</string>
|
||||
<string name="delimiter_semicolon">Semicolon</string>
|
||||
<string name="export_as">Export as?</string>
|
||||
<string name="export_csv_comma">CSV with commas</string>
|
||||
<string name="export_csv_semicolon">CSV with semicolons</string>
|
||||
<string name="export_database">Export SQLite database</string>
|
||||
<string name="saved_in_downloads">Saved in downloads</string>
|
||||
<string name="rotate_image_cw">Rotate image clockwise</string>
|
||||
<string name="pick_file">Pick image file</string>
|
||||
|
||||
@@ -75,9 +75,10 @@
|
||||
<string name="search_web">Search the web</string>
|
||||
<string name="search_scan">Search scan</string>
|
||||
<string name="export_to_file">Export to file</string>
|
||||
<string name="csv_delimiter">Which delimiter should be used (CSV-File)?</string>
|
||||
<string name="delimiter_comma">Comma</string>
|
||||
<string name="delimiter_semicolon">Semicolon</string>
|
||||
<string name="export_as">Export as?</string>
|
||||
<string name="export_csv_comma">CSV with commas</string>
|
||||
<string name="export_csv_semicolon">CSV with semicolons</string>
|
||||
<string name="export_database">Export SQLite database</string>
|
||||
<string name="saved_in_downloads">Saved in downloads</string>
|
||||
<string name="rotate_image_cw">Rotate image clockwise</string>
|
||||
<string name="pick_file">Pick image file</string>
|
||||
|
||||
@@ -78,9 +78,10 @@
|
||||
<string name="search_web">在互联网中搜索</string>
|
||||
<string name="search_scan">Search scan</string>
|
||||
<string name="export_to_file">导出为CSV文件</string>
|
||||
<string name="csv_delimiter">使用哪个分隔符 (CSV-文件)?</string>
|
||||
<string name="delimiter_comma">逗号</string>
|
||||
<string name="delimiter_semicolon">分号</string>
|
||||
<string name="export_as">Export as?</string>
|
||||
<string name="export_csv_comma">CSV with commas</string>
|
||||
<string name="export_csv_semicolon">CSV with semicolons</string>
|
||||
<string name="export_database">Export SQLite database</string>
|
||||
<string name="saved_in_downloads">已保存到下载目录</string>
|
||||
<string name="rotate_image_cw">旋转图片</string>
|
||||
<string name="pick_file">选择图片文件</string>
|
||||
|
||||
@@ -78,9 +78,10 @@
|
||||
<string name="search_web">Search the web</string>
|
||||
<string name="search_scan">Search scan</string>
|
||||
<string name="export_to_file">Export to file</string>
|
||||
<string name="csv_delimiter">Which delimiter should be used (CSV-File)?</string>
|
||||
<string name="delimiter_comma">Comma</string>
|
||||
<string name="delimiter_semicolon">Semicolon</string>
|
||||
<string name="export_as">Export as?</string>
|
||||
<string name="export_csv_comma">CSV with commas</string>
|
||||
<string name="export_csv_semicolon">CSV with semicolons</string>
|
||||
<string name="export_database">Export SQLite database</string>
|
||||
<string name="saved_in_downloads">Saved in downloads</string>
|
||||
<string name="rotate_image_cw">Rotate image clockwise</string>
|
||||
<string name="pick_file">Pick image file</string>
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="csv_delimiters_names">
|
||||
<item>@string/delimiter_comma</item>
|
||||
<item>@string/delimiter_semicolon</item>
|
||||
<string-array name="export_options_names">
|
||||
<item>@string/export_csv_comma</item>
|
||||
<item>@string/export_csv_semicolon</item>
|
||||
<item>@string/export_database</item>
|
||||
</string-array>
|
||||
<string-array name="csv_delimiters_values">
|
||||
<string-array name="export_options_values">
|
||||
<item>,</item>
|
||||
<item>;</item>
|
||||
<item>sql</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
||||
@@ -79,9 +79,10 @@
|
||||
<string name="search_web">Search the web</string>
|
||||
<string name="search_scan">Search scan</string>
|
||||
<string name="export_to_file">Export to file</string>
|
||||
<string name="csv_delimiter">Which delimiter should be used (CSV-File)?</string>
|
||||
<string name="delimiter_comma">Comma</string>
|
||||
<string name="delimiter_semicolon">Semicolon</string>
|
||||
<string name="export_as">Export as?</string>
|
||||
<string name="export_csv_comma">CSV with commas</string>
|
||||
<string name="export_csv_semicolon">CSV with semicolons</string>
|
||||
<string name="export_database">Export SQLite database</string>
|
||||
<string name="saved_in_downloads">Saved in downloads</string>
|
||||
<string name="rotate_image_cw">Rotate image clockwise</string>
|
||||
<string name="pick_file">Pick image file</string>
|
||||
|
||||
Reference in New Issue
Block a user