Merge pull request #620 from Naveen3Singh/parse_exported_notes

Parse exported JSON notes when opening files
This commit is contained in:
Tibor Kaputa 2023-05-04 09:53:17 +02:00 committed by GitHub
commit e3caa53bfa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 81 additions and 42 deletions

View File

@ -42,6 +42,7 @@ import com.simplemobiletools.notes.pro.dialogs.*
import com.simplemobiletools.notes.pro.extensions.* import com.simplemobiletools.notes.pro.extensions.*
import com.simplemobiletools.notes.pro.fragments.TextFragment import com.simplemobiletools.notes.pro.fragments.TextFragment
import com.simplemobiletools.notes.pro.helpers.* import com.simplemobiletools.notes.pro.helpers.*
import com.simplemobiletools.notes.pro.helpers.NotesImporter.ImportResult
import com.simplemobiletools.notes.pro.models.Note import com.simplemobiletools.notes.pro.models.Note
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.item_checklist.* import kotlinx.android.synthetic.main.item_checklist.*
@ -290,7 +291,7 @@ class MainActivity : SimpleActivity() {
val outputStream = contentResolver.openOutputStream(resultData.data!!) val outputStream = contentResolver.openOutputStream(resultData.data!!)
exportNotesTo(outputStream) exportNotesTo(outputStream)
} else if (requestCode == PICK_IMPORT_NOTES_INTENT && resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null) { } else if (requestCode == PICK_IMPORT_NOTES_INTENT && resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null) {
importNotesFrom(resultData.data!!) tryImportingAsJson(resultData.data!!)
} }
} }
@ -729,23 +730,29 @@ class MainActivity : SimpleActivity() {
} }
private fun importUri(uri: Uri) { private fun importUri(uri: Uri) {
when (uri.scheme) { tryImportingAsJson(uri, force = true, showToasts = false) { success ->
"file" -> openPath(uri.path!!) if (success) {
"content" -> { return@tryImportingAsJson
val realPath = getRealPathFromURI(uri) }
if (hasPermission(PERMISSION_READ_STORAGE)) {
if (realPath != null) { when (uri.scheme) {
openPath(realPath) "file" -> openPath(uri.path!!)
"content" -> {
val realPath = getRealPathFromURI(uri)
if (hasPermission(PERMISSION_READ_STORAGE)) {
if (realPath != null) {
openPath(realPath)
} else {
R.string.unknown_error_occurred
}
} else if (realPath != null && realPath != "") {
checkFile(realPath, false) {
addNoteFromUri(uri, realPath.getFilenameFromPath())
}
} else { } else {
R.string.unknown_error_occurred checkUri(uri) {
} addNoteFromUri(uri)
} else if (realPath != null && realPath != "") { }
checkFile(realPath, false) {
addNoteFromUri(uri, realPath.getFilenameFromPath())
}
} else {
checkUri(uri) {
addNoteFromUri(uri)
} }
} }
} }
@ -954,43 +961,66 @@ class MainActivity : SimpleActivity() {
} }
} }
private fun importNotes(path: String, filename: String) { private fun tryImportingAsJson(uri: Uri, force: Boolean = false, showToasts: Boolean = true, callback: ((success: Boolean) -> Unit)? = null) {
toast(R.string.importing) val path: String
ensureBackgroundThread { val filename: String
NotesImporter(this).importNotes(path, filename) {
toast(
when (it) {
NotesImporter.ImportResult.IMPORT_OK -> R.string.importing_successful
NotesImporter.ImportResult.IMPORT_PARTIAL -> R.string.importing_some_entries_failed
else -> R.string.no_new_items
}
)
initViewPager()
}
}
}
private fun importNotesFrom(uri: Uri) {
when (uri.scheme) { when (uri.scheme) {
"file" -> importNotes(uri.path!!, uri.path!!.getFilenameFromPath()) "file" -> {
path = uri.path!!
filename = path.getFilenameFromPath()
}
"content" -> { "content" -> {
val tempFile = getTempFile("messages", "backup.txt") val tempFile = getTempFile("messages", "backup.txt")
if (tempFile == null) { if (tempFile == null) {
toast(R.string.unknown_error_occurred) maybeToast(R.string.unknown_error_occurred, showToasts)
callback?.invoke(false)
return return
} }
try { try {
val filename = getFilenameFromUri(uri) filename = getFilenameFromUri(uri)
val inputStream = contentResolver.openInputStream(uri) val inputStream = contentResolver.openInputStream(uri)
val out = FileOutputStream(tempFile) val out = FileOutputStream(tempFile)
inputStream!!.copyTo(out) inputStream!!.copyTo(out)
importNotes(tempFile.absolutePath, filename) path = tempFile.absolutePath
} catch (e: Exception) { } catch (e: Exception) {
showErrorToast(e) showErrorToast(e)
callback?.invoke(false)
return
} }
} }
else -> toast(R.string.invalid_file_format) else -> {
maybeToast(R.string.invalid_file_format, showToasts)
callback?.invoke(false)
return
}
}
maybeToast(R.string.importing, showToasts)
ensureBackgroundThread {
NotesImporter(this).importNotes(path, filename, force) { importResult ->
if (importResult == ImportResult.IMPORT_FAIL) {
maybeToast(R.string.no_new_items, showToasts)
runOnUiThread { callback?.invoke(false) }
return@importNotes
}
toast(
when (importResult) {
ImportResult.IMPORT_OK -> R.string.importing_successful
ImportResult.IMPORT_PARTIAL -> R.string.importing_some_entries_failed
else -> R.string.no_new_items
}
)
initViewPager()
runOnUiThread { callback?.invoke(true) }
}
}
}
private fun maybeToast(id: Int, show: Boolean) {
if (show) {
toast(id)
} }
} }

View File

@ -19,8 +19,9 @@ class NotesImporter(private val context: Context) {
private val gson = Gson() private val gson = Gson()
private var notesImported = 0 private var notesImported = 0
private var notesFailed = 0 private var notesFailed = 0
private var notesSkipped = 0
fun importNotes(path: String, filename: String, callback: (result: ImportResult) -> Unit) { fun importNotes(path: String, filename: String, force: Boolean = false, callback: (result: ImportResult) -> Unit) {
ensureBackgroundThread { ensureBackgroundThread {
try { try {
val inputStream = if (path.contains("/")) { val inputStream = if (path.contains("/")) {
@ -33,9 +34,9 @@ class NotesImporter(private val context: Context) {
val json = reader.readText() val json = reader.readText()
val type = object : TypeToken<List<Note>>() {}.type val type = object : TypeToken<List<Note>>() {}.type
val notes = gson.fromJson<List<Note>>(json, type) val notes = gson.fromJson<List<Note>>(json, type)
val totalNotes = notes.size val totalNotes = notes?.size ?: 0
if (totalNotes <= 0) { if (totalNotes <= 0) {
callback.invoke(ImportResult.IMPORT_NOTHING_NEW) callback.invoke(ImportResult.IMPORT_FAIL)
return@ensureBackgroundThread return@ensureBackgroundThread
} }
@ -44,10 +45,17 @@ class NotesImporter(private val context: Context) {
if (!exists) { if (!exists) {
context.notesDB.insertOrUpdate(note) context.notesDB.insertOrUpdate(note)
notesImported++ notesImported++
} else {
notesSkipped++
} }
} }
} }
} catch (e: JsonSyntaxException) { } catch (e: JsonSyntaxException) {
if (force) {
callback(ImportResult.IMPORT_FAIL)
return@ensureBackgroundThread
}
// Import notes expects a json with note name, content etc, but lets be more flexible and accept the basic files with note content only too // Import notes expects a json with note name, content etc, but lets be more flexible and accept the basic files with note content only too
val inputStream = if (path.contains("/")) { val inputStream = if (path.contains("/")) {
File(path).inputStream() File(path).inputStream()
@ -82,6 +90,7 @@ class NotesImporter(private val context: Context) {
callback.invoke( callback.invoke(
when { when {
notesSkipped > 0 && notesImported == 0 -> ImportResult.IMPORT_NOTHING_NEW
notesImported == 0 -> ImportResult.IMPORT_FAIL notesImported == 0 -> ImportResult.IMPORT_FAIL
notesFailed > 0 -> ImportResult.IMPORT_PARTIAL notesFailed > 0 -> ImportResult.IMPORT_PARTIAL
else -> ImportResult.IMPORT_OK else -> ImportResult.IMPORT_OK