From 4e9bc35b483de8cf414c772eac4e083e7f75e3a2 Mon Sep 17 00:00:00 2001 From: mateusz-bak <32651935+mateusz-bak@users.noreply.github.com> Date: Sun, 29 May 2022 20:50:35 +0100 Subject: [PATCH] Added option to import books from CSV. --- .../mdev/bookstracker/other/Backup.kt | 106 ++++++++++++++++++ .../mdev/bookstracker/other/Constants.kt | 1 + .../bookstracker/ui/bookslist/ListActivity.kt | 12 ++ .../bookslist/fragments/SettingsFragment.kt | 9 ++ .../drawable/ic_iconscout_file_import_24.xml | 10 ++ app/src/main/res/values-cs-rCZ/strings.xml | 3 + app/src/main/res/values-da-rDK/strings.xml | 3 + app/src/main/res/values-de-rDE/strings.xml | 3 + app/src/main/res/values-el-rGR/strings.xml | 3 + app/src/main/res/values-es-rES/strings.xml | 3 + app/src/main/res/values-fi-rFI/strings.xml | 3 + app/src/main/res/values-fr-rFR/strings.xml | 3 + app/src/main/res/values-hu-rHU/strings.xml | 3 + app/src/main/res/values-it-rIT/strings.xml | 3 + app/src/main/res/values-nl-rNL/strings.xml | 3 + app/src/main/res/values-no-rNO/strings.xml | 3 + app/src/main/res/values-pl-rPL/strings.xml | 3 + app/src/main/res/values-pt-rBR/strings.xml | 3 + app/src/main/res/values-pt-rPT/strings.xml | 3 + app/src/main/res/values-ro-rRO/strings.xml | 3 + app/src/main/res/values-ru-rRU/strings.xml | 3 + app/src/main/res/values-sr-rSP/strings.xml | 3 + app/src/main/res/values-sv-rSE/strings.xml | 3 + app/src/main/res/values-ta-rIN/strings.xml | 3 + app/src/main/res/values-tr-rTR/strings.xml | 3 + app/src/main/res/values-uk-rUA/strings.xml | 3 + app/src/main/res/values/strings.xml | 3 + app/src/main/res/xml/preferences.xml | 6 + 28 files changed, 210 insertions(+) create mode 100644 app/src/main/res/drawable/ic_iconscout_file_import_24.xml diff --git a/app/src/main/java/software/mdev/bookstracker/other/Backup.kt b/app/src/main/java/software/mdev/bookstracker/other/Backup.kt index 608dc44b5..9060415cd 100644 --- a/app/src/main/java/software/mdev/bookstracker/other/Backup.kt +++ b/app/src/main/java/software/mdev/bookstracker/other/Backup.kt @@ -9,6 +9,7 @@ import android.view.View import android.widget.ProgressBar import androidx.core.content.FileProvider.getUriForFile import androidx.sqlite.db.SimpleSQLiteQuery +import com.github.doyaaaaaken.kotlincsv.dsl.csvReader import kotlinx.android.synthetic.main.fragment_add_book_search.* import kotlinx.coroutines.* import software.mdev.bookstracker.BuildConfig @@ -21,6 +22,7 @@ import software.mdev.bookstracker.data.db.entities.Year import software.mdev.bookstracker.ui.bookslist.ListActivity import java.io.* import java.lang.StringBuilder +import java.text.Normalizer import java.text.SimpleDateFormat import java.util.* import java.util.zip.* @@ -125,6 +127,10 @@ class Backup { activity.selectBackup.launch("*/*") } + fun runImporterCSV(activity: ListActivity) { + activity.selectCSV.launch("text/*") + } + // Import a backup overwriting any existing data and checking if the file is valid suspend fun importBackup(context: Context, fileUri: Uri): Boolean { when (validateBackup(fileUri, context)) { @@ -251,6 +257,26 @@ class Backup { } } + fun importCSV(context: Context, fileUri: Uri): Boolean { + try { + val fileStream = context.contentResolver.openInputStream(fileUri)!! + val books = parseGoodReadsCSV(fileStream) + + for (book in books) + (context as ListActivity).booksViewModel.upsert(book) + + (context as ListActivity).showSnackbar(context.getString(R.string.backup_import_success)) + } catch (e: Exception) { + val string = "${context.getString(R.string.csv_import_failure)}: $e" + (context as ListActivity).showSnackbar(string) + e.printStackTrace() + return false + } + + restartActivity(context) + return true + } + private fun zipAll(directory: String, zipFile: String) { val sourceFile = File(directory) val outputZipFile = File(zipFile) @@ -341,4 +367,84 @@ class Backup { progressBar?.bringToFront() } } + + private fun parseGoodReadsCSV(inputStream: InputStream): List { + val rows = csvReader().readAllWithHeader(inputStream) + var newBooks: MutableList = ArrayList() + + for (row in rows) + newBooks.add(parseGoodReadsBook(row)) + + return newBooks + } + + private fun parseGoodReadsBook(row: Map): Book { + val regexUnaccented = "\\p{InCombiningDiacriticalMarks}+".toRegex() + + fun CharSequence.unaccented(): String { + val temp = Normalizer.normalize(this, Normalizer.Form.NFD) + return regexUnaccented.replace(temp, "") + } + + val title = row["Title"] ?: Constants.EMPTY_STRING + + var author: String = row["Author"] ?: Constants.EMPTY_STRING + val additionalAuthors = row["Additional Authors"] ?: Constants.EMPTY_STRING + if (additionalAuthors.isNotEmpty()) + author = "$author, $additionalAuthors" + + var dateAdded = Constants.DATABASE_EMPTY_VALUE + if (row["Date Added"]?.isNotEmpty() == true) { + dateAdded = row["Date Added"]?.let { + SimpleDateFormat("yyyy/MM/dd").parse(it).time + }.toString() + } + + var dateStarted = Constants.DATABASE_EMPTY_VALUE + if (row["Date Started"]?.isNotEmpty() == true) { + dateStarted = row["Date Started"]?.let { + SimpleDateFormat("yyyy/MM/dd").parse(it).time + }.toString() + } + + val bookStatus = when (row["Exclusive Shelf"]) { + "currently-reading" -> Constants.BOOK_STATUS_IN_PROGRESS + "to-read" -> Constants.BOOK_STATUS_TO_READ + else -> Constants.BOOK_STATUS_READ + } + + var dateFinished = Constants.DATABASE_EMPTY_VALUE + if (row["Date Read"]?.isNotEmpty() == true) { + dateFinished = row["Date Read"]?.let { + SimpleDateFormat("yyyy/MM/dd").parse(it).time + }.toString() + } else if (bookStatus == Constants.BOOK_STATUS_READ) { + dateFinished = dateAdded + } + + return Book( + bookTitle = title, + bookAuthor = author, + bookRating = row["My Rating"]?.toFloatOrNull() ?: 0F, + bookStatus = bookStatus, + bookPriority = Constants.DATABASE_EMPTY_VALUE, + bookStartDate = dateStarted, + bookFinishDate = dateFinished, + bookNumberOfPages = row["Number of Pages"]?.toIntOrNull() ?: 0, + bookTitle_ASCII = title.unaccented().replace("ł", "l", false), + bookAuthor_ASCII = author.unaccented().replace("ł", "l", false), + bookIsDeleted = false, + bookCoverUrl = Constants.DATABASE_EMPTY_VALUE, + bookOLID = Constants.DATABASE_EMPTY_VALUE, + bookISBN10 = row["ISBN"]?.removeSurrounding("=\"", "\"") + ?: Constants.DATABASE_EMPTY_VALUE, + bookISBN13 = row["ISBN13"]?.removeSurrounding("=\"", "\"") + ?: Constants.DATABASE_EMPTY_VALUE, + bookPublishYear = row["Original Publication Year"]?.toIntOrNull() ?: 0, + bookIsFav = false, + bookCoverImg = null, + bookNotes = row["My Review"] ?: Constants.DATABASE_EMPTY_VALUE, + bookTags = null, + ) + } } \ No newline at end of file diff --git a/app/src/main/java/software/mdev/bookstracker/other/Constants.kt b/app/src/main/java/software/mdev/bookstracker/other/Constants.kt index dc4c7cc29..a839214fe 100644 --- a/app/src/main/java/software/mdev/bookstracker/other/Constants.kt +++ b/app/src/main/java/software/mdev/bookstracker/other/Constants.kt @@ -112,6 +112,7 @@ object Constants { const val KEY_IMPORT = "KEY_IMPORT" const val KEY_CHANGELOG = "KEY_CHANGELOG" const val KEY_FEEDBACK = "KEY_FEEDBACK" + const val KEY_CSV_IMPORT = "KEY_CSV_IMPORT" const val EMPTY_STRING = "" diff --git a/app/src/main/java/software/mdev/bookstracker/ui/bookslist/ListActivity.kt b/app/src/main/java/software/mdev/bookstracker/ui/bookslist/ListActivity.kt index fd89c1ea7..f263e11cb 100644 --- a/app/src/main/java/software/mdev/bookstracker/ui/bookslist/ListActivity.kt +++ b/app/src/main/java/software/mdev/bookstracker/ui/bookslist/ListActivity.kt @@ -983,6 +983,18 @@ class ListActivity : AppCompatActivity() { } } + val selectCSV = + registerForActivityResult(ActivityResultContracts.GetContent()) { fileUri: Uri? -> + try { + CoroutineScope(Dispatchers.IO).launch { + if (fileUri != null) Backup().importCSV(listActivity, fileUri) + } + } catch (e: IOException) { + showSnackbar(e.toString()) + e.printStackTrace() + } + } + override fun onRequestPermissionsResult( requestCode: Int, permissions: Array, diff --git a/app/src/main/java/software/mdev/bookstracker/ui/bookslist/fragments/SettingsFragment.kt b/app/src/main/java/software/mdev/bookstracker/ui/bookslist/fragments/SettingsFragment.kt index 77c1025e9..9cbd57e3e 100644 --- a/app/src/main/java/software/mdev/bookstracker/ui/bookslist/fragments/SettingsFragment.kt +++ b/app/src/main/java/software/mdev/bookstracker/ui/bookslist/fragments/SettingsFragment.kt @@ -19,6 +19,7 @@ import software.mdev.bookstracker.ui.bookslist.viewmodel.BooksViewModel import android.content.Intent import android.net.Uri import android.os.Build +import software.mdev.bookstracker.other.Backup class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListener { @@ -34,6 +35,7 @@ class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeLis val preferenceChangelog = findPreference(Constants.KEY_CHANGELOG) val preferenceBackup = findPreference(Constants.KEY_BACKUP) val preferenceFeedback = findPreference(Constants.KEY_FEEDBACK) + val preferenceCsvImport = findPreference(Constants.KEY_CSV_IMPORT) if (preferenceCheckForUpdates != null) { val updater = Updater() @@ -73,6 +75,13 @@ class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeLis true } } + + if (preferenceCsvImport != null) { + preferenceCsvImport.onPreferenceClickListener = Preference.OnPreferenceClickListener { + Backup().runImporterCSV(activity as ListActivity) + true + } + } } override fun onResume() { diff --git a/app/src/main/res/drawable/ic_iconscout_file_import_24.xml b/app/src/main/res/drawable/ic_iconscout_file_import_24.xml new file mode 100644 index 000000000..a10a88807 --- /dev/null +++ b/app/src/main/res/drawable/ic_iconscout_file_import_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index db835355b..e0d90ba43 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -295,4 +295,7 @@ Fixed backup in F-Droid variant. Improved backup for bigger libraries. Improved translations. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-da-rDK/strings.xml b/app/src/main/res/values-da-rDK/strings.xml index d4a8fe096..d2d98dda0 100644 --- a/app/src/main/res/values-da-rDK/strings.xml +++ b/app/src/main/res/values-da-rDK/strings.xml @@ -295,4 +295,7 @@ Fast backup i F-Droid variant. Forbedret backup af større biblioteker. Forbedrede oversættelser. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index bd189cd49..4477a2285 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -295,4 +295,7 @@ Fehlerkorrektur in F-Droid Variante. Verbessertes Backup für größere Bibliotheken. Verbesserte Übersetzungen. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-el-rGR/strings.xml b/app/src/main/res/values-el-rGR/strings.xml index db835355b..e0d90ba43 100644 --- a/app/src/main/res/values-el-rGR/strings.xml +++ b/app/src/main/res/values-el-rGR/strings.xml @@ -295,4 +295,7 @@ Fixed backup in F-Droid variant. Improved backup for bigger libraries. Improved translations. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index 66e0605c5..942955d9e 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -295,4 +295,7 @@ Copia de seguridad fija en la variante F-Droid. Copia de seguridad mejorada para bibliotecas más grandes. Traducciones mejoradas. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index db835355b..e0d90ba43 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -295,4 +295,7 @@ Fixed backup in F-Droid variant. Improved backup for bigger libraries. Improved translations. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml index 35af274ee..f7a1d3545 100644 --- a/app/src/main/res/values-fr-rFR/strings.xml +++ b/app/src/main/res/values-fr-rFR/strings.xml @@ -295,4 +295,7 @@ Sauvegarde réparée dans la variante F-Droid. Amélioration de la sauvegarde pour les bibliothèques plus grandes. Traductions améliorées. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index db835355b..e0d90ba43 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -295,4 +295,7 @@ Fixed backup in F-Droid variant. Improved backup for bigger libraries. Improved translations. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml index be68ce915..9b0447c52 100644 --- a/app/src/main/res/values-it-rIT/strings.xml +++ b/app/src/main/res/values-it-rIT/strings.xml @@ -295,4 +295,7 @@ Backup fisso nella variante F-Droid. Backup migliorato per librerie più grandi. Traduzioni migliorate. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-nl-rNL/strings.xml b/app/src/main/res/values-nl-rNL/strings.xml index db835355b..e0d90ba43 100644 --- a/app/src/main/res/values-nl-rNL/strings.xml +++ b/app/src/main/res/values-nl-rNL/strings.xml @@ -295,4 +295,7 @@ Fixed backup in F-Droid variant. Improved backup for bigger libraries. Improved translations. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-no-rNO/strings.xml b/app/src/main/res/values-no-rNO/strings.xml index db835355b..e0d90ba43 100644 --- a/app/src/main/res/values-no-rNO/strings.xml +++ b/app/src/main/res/values-no-rNO/strings.xml @@ -295,4 +295,7 @@ Fixed backup in F-Droid variant. Improved backup for bigger libraries. Improved translations. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml index 7fffae3b1..07f5f0075 100644 --- a/app/src/main/res/values-pl-rPL/strings.xml +++ b/app/src/main/res/values-pl-rPL/strings.xml @@ -295,4 +295,7 @@ Naprawiono kopię zapasową w wariancie F-Droid. Ulepszono kopię zapasową dla większych bilbiotek. Ulepszono tłumaczenia. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 9a0e5f97d..9e2e3f1f1 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -295,4 +295,7 @@ Fixed backup in F-Droid variant. Improved backup for bigger libraries. Improved translations. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index db835355b..e0d90ba43 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -295,4 +295,7 @@ Fixed backup in F-Droid variant. Improved backup for bigger libraries. Improved translations. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-ro-rRO/strings.xml b/app/src/main/res/values-ro-rRO/strings.xml index db835355b..e0d90ba43 100644 --- a/app/src/main/res/values-ro-rRO/strings.xml +++ b/app/src/main/res/values-ro-rRO/strings.xml @@ -295,4 +295,7 @@ Fixed backup in F-Droid variant. Improved backup for bigger libraries. Improved translations. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index db835355b..e0d90ba43 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -295,4 +295,7 @@ Fixed backup in F-Droid variant. Improved backup for bigger libraries. Improved translations. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-sr-rSP/strings.xml b/app/src/main/res/values-sr-rSP/strings.xml index db835355b..e0d90ba43 100644 --- a/app/src/main/res/values-sr-rSP/strings.xml +++ b/app/src/main/res/values-sr-rSP/strings.xml @@ -295,4 +295,7 @@ Fixed backup in F-Droid variant. Improved backup for bigger libraries. Improved translations. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-sv-rSE/strings.xml b/app/src/main/res/values-sv-rSE/strings.xml index db835355b..e0d90ba43 100644 --- a/app/src/main/res/values-sv-rSE/strings.xml +++ b/app/src/main/res/values-sv-rSE/strings.xml @@ -295,4 +295,7 @@ Fixed backup in F-Droid variant. Improved backup for bigger libraries. Improved translations. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-ta-rIN/strings.xml b/app/src/main/res/values-ta-rIN/strings.xml index db835355b..e0d90ba43 100644 --- a/app/src/main/res/values-ta-rIN/strings.xml +++ b/app/src/main/res/values-ta-rIN/strings.xml @@ -295,4 +295,7 @@ Fixed backup in F-Droid variant. Improved backup for bigger libraries. Improved translations. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-tr-rTR/strings.xml b/app/src/main/res/values-tr-rTR/strings.xml index db835355b..e0d90ba43 100644 --- a/app/src/main/res/values-tr-rTR/strings.xml +++ b/app/src/main/res/values-tr-rTR/strings.xml @@ -295,4 +295,7 @@ Fixed backup in F-Droid variant. Improved backup for bigger libraries. Improved translations. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values-uk-rUA/strings.xml b/app/src/main/res/values-uk-rUA/strings.xml index db835355b..e0d90ba43 100644 --- a/app/src/main/res/values-uk-rUA/strings.xml +++ b/app/src/main/res/values-uk-rUA/strings.xml @@ -295,4 +295,7 @@ Fixed backup in F-Droid variant. Improved backup for bigger libraries. Improved translations. + Migrate from other reading apps + Import books from CSV + CSV import failed diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1f59c1257..f324e8855 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -327,4 +327,7 @@ Fixed backup in F-Droid variant. Improved backup for bigger libraries. Improved translations. + Migrate from other reading apps + Import books from CSV + CSV import failed \ No newline at end of file diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 3cec39ad4..3c03749c5 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -28,6 +28,12 @@ android:summary="@string/backup_summary" android:title="@string/backup_title" /> + +