mirror of
https://github.com/mihonapp/mihon.git
synced 2025-03-16 17:45:14 +01:00
Separate to new file
This commit is contained in:
parent
b3c1a683e7
commit
87f50551c8
@ -52,6 +52,7 @@ import eu.kanade.presentation.util.relativeTimeSpanString
|
|||||||
import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob
|
import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob
|
||||||
import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreJob
|
import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreJob
|
||||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||||
|
import eu.kanade.tachiyomi.data.export.LibraryExporter
|
||||||
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
import eu.kanade.tachiyomi.util.system.DeviceUtil
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
@ -338,31 +339,23 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
val favoritesFlow = remember { flow { emit(getFavorites.await()) } }
|
val favoritesFlow = remember { flow { emit(getFavorites.await()) } }
|
||||||
val favoritesState by favoritesFlow.collectAsState(emptyList())
|
val favoritesState by favoritesFlow.collectAsState(emptyList())
|
||||||
|
|
||||||
|
val libraryExporter = LibraryExporter()
|
||||||
|
|
||||||
val saveFileLauncher = rememberLauncherForActivityResult(
|
val saveFileLauncher = rememberLauncherForActivityResult(
|
||||||
contract = ActivityResultContracts.CreateDocument("text/csv"),
|
contract = ActivityResultContracts.CreateDocument("text/csv"),
|
||||||
) { uri ->
|
) { uri ->
|
||||||
uri?.let {
|
uri?.let {
|
||||||
coroutineScope.launch {
|
libraryExporter.exportToCsv(
|
||||||
context.contentResolver.openOutputStream(uri)?.use { outputStream ->
|
context,
|
||||||
val csvData = buildString {
|
it,
|
||||||
favoritesState.forEach { manga ->
|
favoritesState,
|
||||||
val title = if (titleSelected) escapeCsvField(manga.title) else ""
|
LibraryExporter.ExportOptions(titleSelected, authorSelected, artistSelected),
|
||||||
val author = if (authorSelected) escapeCsvField(manga.author ?: "") else ""
|
coroutineScope
|
||||||
val artist = if (artistSelected) escapeCsvField(manga.artist ?: "") else ""
|
) {
|
||||||
val row = listOf(title, author, artist).filter {
|
|
||||||
it.isNotEmpty()
|
|
||||||
}.joinToString(",") { "\"$it\"" }
|
|
||||||
appendLine(row)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outputStream.write(csvData.toByteArray())
|
|
||||||
outputStream.flush()
|
|
||||||
|
|
||||||
context.toast(MR.strings.library_exported)
|
context.toast(MR.strings.library_exported)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (showDialog) {
|
if (showDialog) {
|
||||||
ColumnSelectionDialog(
|
ColumnSelectionDialog(
|
||||||
@ -390,13 +383,6 @@ object SettingsDataScreen : SearchableSettings {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun escapeCsvField(field: String): String {
|
|
||||||
return field
|
|
||||||
.replace("\"", "\"\"")
|
|
||||||
.replace("\r\n", "\n")
|
|
||||||
.replace("\r", "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ColumnSelectionDialog(
|
private fun ColumnSelectionDialog(
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
package eu.kanade.tachiyomi.data.export
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.net.Uri
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import tachiyomi.domain.manga.model.Manga
|
||||||
|
|
||||||
|
class LibraryExporter {
|
||||||
|
|
||||||
|
data class ExportOptions(
|
||||||
|
val includeTitle: Boolean,
|
||||||
|
val includeAuthor: Boolean,
|
||||||
|
val includeArtist: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
fun exportToCsv(
|
||||||
|
context: Context,
|
||||||
|
uri: Uri,
|
||||||
|
favorites: List<Manga>,
|
||||||
|
options: ExportOptions,
|
||||||
|
coroutineScope: CoroutineScope,
|
||||||
|
onExportComplete: () -> Unit
|
||||||
|
) {
|
||||||
|
coroutineScope.launch {
|
||||||
|
context.contentResolver.openOutputStream(uri)?.use { outputStream ->
|
||||||
|
val csvData = generateCsvData(favorites, options)
|
||||||
|
outputStream.write(csvData.toByteArray())
|
||||||
|
outputStream.flush()
|
||||||
|
onExportComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateCsvData(favorites: List<Manga>, options: ExportOptions): String {
|
||||||
|
val stringBuilder = StringBuilder()
|
||||||
|
favorites.forEach { manga ->
|
||||||
|
val row = mutableListOf<String>()
|
||||||
|
if (options.includeTitle) row.add(escapeCsvField(manga.title))
|
||||||
|
if (options.includeAuthor) row.add(escapeCsvField(manga.author ?: ""))
|
||||||
|
if (options.includeArtist) row.add(escapeCsvField(manga.artist ?: ""))
|
||||||
|
if (row.isNotEmpty()) {
|
||||||
|
stringBuilder.appendLine(row.joinToString(",") { "\"$it\"" })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stringBuilder.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun escapeCsvField(field: String): String {
|
||||||
|
return field
|
||||||
|
.replace("\"", "\"\"")
|
||||||
|
.replace("\r\n", "\n")
|
||||||
|
.replace("\r", "\n")
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user