- fixed app crash when gson can not deserialize note

- create checklist notes if user paste note with new line char
This commit is contained in:
Pavol Franek 2020-03-01 16:53:09 +01:00
parent 86714229b4
commit 7b12650db9
4 changed files with 75 additions and 68 deletions

View File

@ -59,7 +59,7 @@ class NotesPagerAdapter(fm: FragmentManager, val notes: List<Note>, val activity
fun saveAllFragmentTexts() = fragments.values.forEach { (it as? TextFragment)?.saveText(false) }
fun getNoteChecklistItems(position: Int) = (fragments[position] as? ChecklistFragment)?.getChecklistItems()
fun getNoteChecklistItems(position: Int) = (fragments[position] as? ChecklistFragment)?.checklistItems
fun undo(position: Int) = (fragments[position] as? TextFragment)?.undo()

View File

@ -2,8 +2,11 @@ package com.simplemobiletools.notes.pro.extensions
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.simplemobiletools.notes.pro.BuildConfig
import com.simplemobiletools.notes.pro.helpers.Config
val Fragment.config: Config? get() = if (context != null) Config.newInstance(context!!) else null
val Fragment.requiredActivity: FragmentActivity get() = this.activity!!
val Fragment.isDebug get(): Boolean = BuildConfig.DEBUG

View File

@ -13,12 +13,8 @@ import com.simplemobiletools.notes.pro.R
import com.simplemobiletools.notes.pro.activities.SimpleActivity
import com.simplemobiletools.notes.pro.adapters.ChecklistAdapter
import com.simplemobiletools.notes.pro.dialogs.NewChecklistItemDialog
import com.simplemobiletools.notes.pro.extensions.config
import com.simplemobiletools.notes.pro.extensions.notesDB
import com.simplemobiletools.notes.pro.extensions.requiredActivity
import com.simplemobiletools.notes.pro.extensions.updateWidgets
import com.simplemobiletools.notes.pro.extensions.*
import com.simplemobiletools.notes.pro.helpers.NOTE_ID
import com.simplemobiletools.notes.pro.helpers.NoteType
import com.simplemobiletools.notes.pro.helpers.NotesHelper
import com.simplemobiletools.notes.pro.interfaces.ChecklistItemsListener
import com.simplemobiletools.notes.pro.models.ChecklistItem
@ -26,14 +22,17 @@ import com.simplemobiletools.notes.pro.models.Note
import kotlinx.android.synthetic.main.fragment_checklist.view.*
class ChecklistFragment : NoteFragment(), ChecklistItemsListener {
private var noteId = 0L
private var noteId = 0L
private var items = ArrayList<ChecklistItem>()
private var note: Note? = null
private var items = ArrayList<ChecklistItem>()
lateinit var view: ViewGroup
val checklistItems get(): String = Gson().toJson(items)
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
view = inflater.inflate(R.layout.fragment_checklist, container, false) as ViewGroup
view = inflater.inflate(R.layout.fragment_checklist, container, false) as ViewGroup
noteId = arguments!!.getLong(NOTE_ID, 0L)
return view
}
@ -41,41 +40,39 @@ class ChecklistFragment : NoteFragment(), ChecklistItemsListener {
override fun onResume() {
super.onResume()
NotesHelper(requiredActivity).getNoteWithId(noteId) {
if (it != null && activity?.isDestroyed == false) {
note = it
loadNoteById(noteId)
}
override fun setMenuVisibility(menuVisible: Boolean) {
super.setMenuVisibility(menuVisible)
if (menuVisible) activity?.hideKeyboard()
}
private fun loadNoteById(noteId: Long) {
NotesHelper(requiredActivity).getNoteWithId(noteId) { storedNote ->
if (storedNote != null && activity?.isDestroyed == false) {
note = storedNote
try {
val checklistItemType = object : TypeToken<List<ChecklistItem>>() {}.type
items = Gson().fromJson<ArrayList<ChecklistItem>>(note!!.value, checklistItemType) ?: ArrayList(1)
val checklistItemType = object: TypeToken<List<ChecklistItem>>(){}.type
items = Gson().fromJson<ArrayList<ChecklistItem>>(storedNote.value, checklistItemType) ?: ArrayList(1)
} catch (e: Exception) {
note?.run { migrateCheckListOnFailure(it) }
e.printStackTrace()
}
if (config!!.moveUndoneChecklistItems) {
items.sortBy { it.isDone }
migrateCheckListOnFailure(storedNote)
if (isDebug) e.printStackTrace()
}
if (config?.moveUndoneChecklistItems == true) items.sortBy { it.isDone }
requiredActivity.updateTextColors(view.checklist_holder)
setupFragment()
}
}
}
override fun setMenuVisibility(menuVisible: Boolean) {
super.setMenuVisibility(menuVisible)
if (menuVisible) {
activity?.hideKeyboard()
}
}
private fun migrateCheckListOnFailure(note: Note) {
items.clear()
val notes = note.value.split("\n").map { it.trim() }.filter { it.isNotBlank() }
notes.forEachIndexed { index, value ->
note.value.split("\n").map { it.trim() }.filter { it.isNotBlank() }.forEachIndexed { index, value ->
items.add(ChecklistItem(
id = index,
title = value,
@ -88,8 +85,9 @@ class ChecklistFragment : NoteFragment(), ChecklistItemsListener {
private fun setupFragment() {
val plusIcon = resources.getColoredDrawableWithColor(R.drawable.ic_plus_vector, if (requiredActivity.isBlackAndWhiteTheme()) Color.BLACK else Color.WHITE)
view.apply {
checklist_fab.apply {
with(checklist_fab) {
setImageDrawable(plusIcon)
background.applyColorFilter(requiredActivity.getAdjustedPrimaryColor())
setOnClickListener {
@ -97,7 +95,7 @@ class ChecklistFragment : NoteFragment(), ChecklistItemsListener {
}
}
fragment_placeholder_2.apply {
with(fragment_placeholder_2) {
setTextColor(requiredActivity.getAdjustedPrimaryColor())
underlineText()
setOnClickListener {
@ -105,36 +103,45 @@ class ChecklistFragment : NoteFragment(), ChecklistItemsListener {
}
}
}
setupAdapter()
}
private fun showNewItemDialog() {
NewChecklistItemDialog(activity as SimpleActivity) {
var currentMaxId = items.maxBy { it.id }?.id ?: 0
it.forEach {
val checklistItem = ChecklistItem(currentMaxId + 1, it, false)
items.add(checklistItem)
currentMaxId++
NewChecklistItemDialog(activity as SimpleActivity) { titles ->
var currentMaxId = items.maxBy { item -> item.id }?.id ?: 0
titles.forEach { title ->
title.split("\n").map { it.trim() }.filter { it.isNotBlank() }.forEach { row ->
items.add(ChecklistItem(currentMaxId + 1, row, false))
currentMaxId++
}
}
saveNote()
if (items.size == it.size) {
setupAdapter()
} else {
(view.checklist_list.adapter as? ChecklistAdapter)?.notifyDataSetChanged()
}
setupAdapter()
(view.checklist_list.adapter as? ChecklistAdapter)?.notifyDataSetChanged()
}
}
private fun setupAdapter() {
view.apply {
with(view) {
fragment_placeholder.beVisibleIf(items.isEmpty())
fragment_placeholder_2.beVisibleIf(items.isEmpty())
checklist_list.beVisibleIf(items.isNotEmpty())
}
ChecklistAdapter(activity as SimpleActivity, items, this, view.checklist_list, true) {
val clickedNote = it as ChecklistItem
ChecklistAdapter(
activity = activity as SimpleActivity,
items = items,
listener = this,
recyclerView = view.checklist_list,
showIcons = true
) { item ->
val clickedNote = item as ChecklistItem
clickedNote.isDone = !clickedNote.isDone
saveNote(items.indexOfFirst { it.id == clickedNote.id })
context?.updateWidgets()
}.apply {
@ -144,27 +151,22 @@ class ChecklistFragment : NoteFragment(), ChecklistItemsListener {
private fun saveNote(refreshIndex: Int = -1) {
ensureBackgroundThread {
if (note != null && context != null) {
if (refreshIndex != -1) {
view.checklist_list.post {
view.checklist_list.adapter?.notifyItemChanged(refreshIndex)
context?.let { ctx ->
note?.let { currentNote ->
if (refreshIndex != -1) {
view.checklist_list.post {
view.checklist_list.adapter?.notifyItemChanged(refreshIndex)
}
}
}
note!!.value = getChecklistItems()
context?.notesDB?.insertOrUpdate(note!!)
context?.updateWidgets()
currentNote.value = checklistItems
ctx.notesDB.insertOrUpdate(currentNote)
ctx.updateWidgets()
}
}
}
}
fun getChecklistItems() = Gson().toJson(items)
override fun saveChecklist() {
saveNote()
}
override fun refreshItems() {
setupAdapter()
}
override fun saveChecklist() { saveNote() }
override fun refreshItems() { setupAdapter() }
}

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/dialog_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -15,8 +14,9 @@
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/medium_margin"
android:inputType="textCapSentences"
android:maxLength="500"
android:textCursorDrawable="@null"
android:textSize="@dimen/normal_text_size"/>
android:textSize="@dimen/normal_text_size" />
<com.simplemobiletools.commons.views.MyEditText
android:id="@+id/checklist_item_title_2"
@ -24,8 +24,9 @@
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/medium_margin"
android:inputType="textCapSentences"
android:maxLength="500"
android:textCursorDrawable="@null"
android:textSize="@dimen/normal_text_size"/>
android:textSize="@dimen/normal_text_size" />
<com.simplemobiletools.commons.views.MyEditText
android:id="@+id/checklist_item_title_3"
@ -33,7 +34,8 @@
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/medium_margin"
android:inputType="textCapSentences"
android:maxLength="500"
android:textCursorDrawable="@null"
android:textSize="@dimen/normal_text_size"/>
android:textSize="@dimen/normal_text_size" />
</LinearLayout>