Skip to content

Commit 57f8f66

Browse files
committed
Use list adapter for checklists
1 parent 9fed832 commit 57f8f66

File tree

8 files changed

+97
-91
lines changed

8 files changed

+97
-91
lines changed

app/src/main/kotlin/org/fossify/notes/activities/WidgetConfigureActivity.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,10 +171,12 @@ class WidgetConfigureActivity : SimpleActivity() {
171171
}
172172
}
173173

174-
ChecklistAdapter(this, items, null, binding.checklistNoteView, false) {}.apply {
174+
ChecklistAdapter(this, null, binding.checklistNoteView).apply {
175175
updateTextColor(mTextColor)
176176
binding.checklistNoteView.adapter = this
177+
submitList(items.toList())
177178
}
179+
178180
binding.textNoteView.beGone()
179181
binding.checklistNoteView.beVisible()
180182
} else {

app/src/main/kotlin/org/fossify/notes/adapters/ChecklistAdapter.kt

Lines changed: 57 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ import android.view.Menu
77
import android.view.MotionEvent
88
import android.view.View
99
import android.view.ViewGroup
10+
import androidx.recyclerview.widget.DiffUtil
1011
import androidx.recyclerview.widget.ItemTouchHelper
1112
import androidx.recyclerview.widget.RecyclerView
1213
import org.fossify.commons.activities.BaseSimpleActivity
1314
import org.fossify.commons.adapters.MyRecyclerViewAdapter
15+
import org.fossify.commons.adapters.MyRecyclerViewListAdapter
1416
import org.fossify.commons.extensions.applyColorFilter
1517
import org.fossify.commons.extensions.beVisibleIf
1618
import org.fossify.commons.extensions.removeBit
@@ -31,18 +33,19 @@ import java.util.Collections
3133

3234
class ChecklistAdapter(
3335
activity: BaseSimpleActivity,
34-
var items: MutableList<ChecklistItem>,
3536
val listener: ChecklistItemsListener?,
3637
recyclerView: MyRecyclerView,
37-
val showIcons: Boolean,
38-
itemClick: (Any) -> Unit,
39-
) : MyRecyclerViewAdapter(activity, recyclerView, itemClick), ItemTouchHelperContract {
38+
itemClick: (Any) -> Unit = {},
39+
) : MyRecyclerViewListAdapter<ChecklistItem>(
40+
activity = activity, recyclerView = recyclerView, diffUtil = ChecklistItemDiffUtil(), itemClick = itemClick
41+
), ItemTouchHelperContract {
4042

4143
private var touchHelper: ItemTouchHelper? = null
4244
private var startReorderDragListener: StartReorderDragListener
4345

4446
init {
4547
setupDragListener(true)
48+
setHasStableIds(true)
4649

4750
touchHelper = ItemTouchHelper(ItemMoveCallback(this))
4851
touchHelper!!.attachToRecyclerView(recyclerView)
@@ -69,23 +72,21 @@ class ChecklistAdapter(
6972
}
7073
}
7174

72-
override fun getSelectableItemCount() = items.size
75+
override fun getItemId(position: Int) = currentList[position].id.toLong()
76+
77+
override fun getSelectableItemCount() = currentList.size
7378

7479
override fun getIsItemSelectable(position: Int) = true
7580

76-
override fun getItemSelectionKey(position: Int) = items.getOrNull(position)?.id
81+
override fun getItemSelectionKey(position: Int) = currentList.getOrNull(position)?.id
7782

78-
override fun getItemKeyPosition(key: Int) = items.indexOfFirst { it.id == key }
83+
override fun getItemKeyPosition(key: Int) = currentList.indexOfFirst { it.id == key }
7984

8085
@SuppressLint("NotifyDataSetChanged")
81-
override fun onActionModeCreated() {
82-
notifyDataSetChanged()
83-
}
86+
override fun onActionModeCreated() = notifyDataSetChanged()
8487

8588
@SuppressLint("NotifyDataSetChanged")
86-
override fun onActionModeDestroyed() {
87-
notifyDataSetChanged()
88-
}
89+
override fun onActionModeDestroyed() = notifyDataSetChanged()
8990

9091
override fun prepareActionMode(menu: Menu) {
9192
val selectedItems = getSelectedItems()
@@ -101,93 +102,70 @@ class ChecklistAdapter(
101102
}
102103

103104
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
104-
val item = items[position]
105+
val item = currentList[position]
105106
holder.bindView(item, allowSingleClick = true, allowLongClick = true) { itemView, _ ->
106107
setupView(itemView, item, holder)
107108
}
108109

109110
bindViewHolder(holder)
110111
}
111112

112-
override fun getItemCount() = items.size
113-
114113
private fun renameChecklistItem() {
115114
val item = getSelectedItems().first()
116-
RenameChecklistItemDialog(activity, item.title) {
117-
val position = getSelectedItemPositions().first()
118-
item.title = it
119-
notifyItemChanged(position)
115+
RenameChecklistItemDialog(activity, item.title) { title ->
116+
val items = currentList.toMutableList()
117+
items[getSelectedItemPositions().first()] = item.copy(title = title)
118+
saveChecklist(items)
120119
finishActMode()
121-
listener?.saveChecklist {
122-
listener.refreshItems()
123-
}
124120
}
125121
}
126122

127123
private fun deleteSelection() {
128-
val removeItems = ArrayList<ChecklistItem>(selectedKeys.size)
129-
val positions = ArrayList<Int>()
130-
selectedKeys.forEach {
131-
val key = it
124+
val items = currentList.toMutableList()
125+
val itemsToRemove = ArrayList<ChecklistItem>(selectedKeys.size)
126+
selectedKeys.forEach { key ->
132127
val position = items.indexOfFirst { it.id == key }
133128
if (position != -1) {
134-
positions.add(position)
135-
136129
val favorite = getItemWithKey(key)
137130
if (favorite != null) {
138-
removeItems.add(favorite)
131+
itemsToRemove.add(favorite)
139132
}
140133
}
141134
}
142135

143-
items.removeAll(removeItems.toSet())
144-
positions.sortDescending()
145-
removeSelectedItems(positions)
146-
147-
listener?.saveChecklist {
148-
if (items.isEmpty()) {
149-
listener.refreshItems()
150-
}
151-
}
136+
items.removeAll(itemsToRemove.toSet())
137+
saveChecklist(items)
152138
}
153139

154140
private fun moveSelectedItemsToTop() {
155141
activity.config.sorting = SORT_BY_CUSTOM
156-
val movedPositions = mutableListOf<Int>()
142+
val items = currentList.toMutableList()
157143
selectedKeys.reversed().forEach { checklistId ->
158144
val position = items.indexOfFirst { it.id == checklistId }
159145
val tempItem = items[position]
160146
items.removeAt(position)
161-
movedPositions.add(position)
162147
items.add(0, tempItem)
163148
}
164149

165-
movedPositions.forEach {
166-
notifyItemMoved(it, 0)
167-
}
168-
listener?.saveChecklist()
150+
saveChecklist(items)
169151
}
170152

171153
private fun moveSelectedItemsToBottom() {
172154
activity.config.sorting = SORT_BY_CUSTOM
173-
val movedPositions = mutableListOf<Int>()
155+
val items = currentList.toMutableList()
174156
selectedKeys.forEach { checklistId ->
175157
val position = items.indexOfFirst { it.id == checklistId }
176158
val tempItem = items[position]
177159
items.removeAt(position)
178-
movedPositions.add(position)
179160
items.add(items.size, tempItem)
180161
}
181162

182-
movedPositions.forEach {
183-
notifyItemMoved(it, items.size - 1)
184-
}
185-
listener?.saveChecklist()
163+
saveChecklist(items)
186164
}
187165

188-
private fun getItemWithKey(key: Int): ChecklistItem? = items.firstOrNull { it.id == key }
166+
private fun getItemWithKey(key: Int): ChecklistItem? = currentList.firstOrNull { it.id == key }
189167

190-
private fun getSelectedItems() = items.filter { selectedKeys.contains(it.id) } as ArrayList<ChecklistItem>
168+
private fun getSelectedItems() = currentList.filter { selectedKeys.contains(it.id) }.toMutableList()
191169

192170
private fun setupView(view: View, checklistItem: ChecklistItem, holder: ViewHolder) {
193171
val isSelected = selectedKeys.contains(checklistItem.id)
@@ -223,6 +201,7 @@ class ChecklistAdapter(
223201

224202
override fun onRowMoved(fromPosition: Int, toPosition: Int) {
225203
activity.config.sorting = SORT_BY_CUSTOM
204+
val items = currentList.toMutableList()
226205
if (fromPosition < toPosition) {
227206
for (i in fromPosition until toPosition) {
228207
Collections.swap(items, i, i + 1)
@@ -232,13 +211,34 @@ class ChecklistAdapter(
232211
Collections.swap(items, i, i - 1)
233212
}
234213
}
235-
notifyItemMoved(fromPosition, toPosition)
214+
215+
saveChecklist(items)
236216
}
237217

238-
override fun onRowSelected(myViewHolder: ViewHolder?) {
218+
override fun onRowSelected(myViewHolder: MyRecyclerViewAdapter.ViewHolder?) {}
219+
220+
override fun onRowClear(myViewHolder: MyRecyclerViewAdapter.ViewHolder?) {
221+
saveChecklist(currentList.toList())
239222
}
240223

241-
override fun onRowClear(myViewHolder: ViewHolder?) {
242-
listener?.saveChecklist()
224+
private fun saveChecklist(items: List<ChecklistItem>) {
225+
listener?.saveChecklist(items) {
226+
listener.refreshItems()
227+
}
243228
}
244229
}
230+
231+
private class ChecklistItemDiffUtil : DiffUtil.ItemCallback<ChecklistItem>() {
232+
override fun areItemsTheSame(
233+
oldItem: ChecklistItem,
234+
newItem: ChecklistItem
235+
) = oldItem.id == newItem.id
236+
237+
override fun areContentsTheSame(
238+
oldItem: ChecklistItem,
239+
newItem: ChecklistItem
240+
) = oldItem.id == newItem.id
241+
&& oldItem.isDone == newItem.isDone
242+
&& oldItem.title == newItem.title
243+
&& oldItem.dateCreated == newItem.dateCreated
244+
}

app/src/main/kotlin/org/fossify/notes/adapters/OpenNoteAdapter.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ class OpenNoteAdapter(
124124
NoteType.TYPE_CHECKLIST -> {
125125
val checklistItemType = object : TypeToken<List<ChecklistItem>>() {}.type
126126
var items = Gson().fromJson<List<ChecklistItem>>(getNoteStoredValue(context), checklistItemType) ?: listOf()
127-
items = items.filter { it.title != null }.let {
127+
items = items.let {
128128
val sorting = context.config.sorting
129129
ChecklistItem.sorting = sorting
130130
if (ChecklistItem.sorting and SORT_BY_CUSTOM == 0) {

app/src/main/kotlin/org/fossify/notes/adapters/WidgetAdapter.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,11 @@ class WidgetAdapter(val context: Context, val intent: Intent) : RemoteViewsServi
128128
checklistItems = note!!.getNoteStoredValue(context)?.ifEmpty { "[]" }?.let { Json.decodeFromString(it) } ?: mutableListOf()
129129

130130
// checklist title can be null only because of the glitch in upgrade to 6.6.0, remove this check in the future
131-
checklistItems = checklistItems.filter { it.title != null }.toMutableList() as ArrayList<ChecklistItem>
131+
checklistItems = checklistItems.toMutableList() as ArrayList<ChecklistItem>
132132
val sorting = context.config.sorting
133133
if (sorting and SORT_BY_CUSTOM == 0) {
134134
checklistItems.sort()
135-
if (context.config?.moveDoneChecklistItems == true) {
135+
if (context.config.moveDoneChecklistItems) {
136136
checklistItems.sortBy { it.isDone }
137137
}
138138
}

app/src/main/kotlin/org/fossify/notes/fragments/ChecklistFragment.kt

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,7 @@ class ChecklistFragment : NoteFragment(), ChecklistItemsListener {
6363
val checklistItemType = object : TypeToken<List<ChecklistItem>>() {}.type
6464
items = Gson().fromJson<ArrayList<ChecklistItem>>(storedNote.getNoteStoredValue(requireActivity()), checklistItemType) ?: ArrayList(1)
6565

66-
// checklist title can be null only because of the glitch in upgrade to 6.6.0, remove this check in the future
67-
items = items.filter { it.title != null }.toMutableList() as ArrayList<ChecklistItem>
66+
items = items.toMutableList() as ArrayList<ChecklistItem>
6867
val sorting = config?.sorting ?: 0
6968
if (sorting and SORT_BY_CUSTOM == 0 && config?.moveDoneChecklistItems == true) {
7069
items.sortBy { it.isDone }
@@ -91,7 +90,7 @@ class ChecklistFragment : NoteFragment(), ChecklistItemsListener {
9190
)
9291
}
9392

94-
saveChecklist()
93+
saveChecklist(items)
9594
}
9695

9796
private fun setupFragment() {
@@ -173,25 +172,33 @@ class ChecklistFragment : NoteFragment(), ChecklistItemsListener {
173172
items.sortBy { it.isDone }
174173
}
175174
}
176-
ChecklistAdapter(
177-
activity = activity as SimpleActivity,
178-
items = items,
179-
listener = this,
180-
recyclerView = binding.checklistList,
181-
showIcons = true
182-
) { item ->
183-
val clickedNote = item as ChecklistItem
184-
clickedNote.isDone = !clickedNote.isDone
185-
186-
saveNote(items.indexOfFirst { it.id == clickedNote.id })
187-
context?.updateWidgets()
188-
refreshItems()
189-
}.apply {
190-
binding.checklistList.adapter = this
175+
176+
var checklistAdapter = binding.checklistList.adapter as? ChecklistAdapter
177+
if (checklistAdapter == null) {
178+
checklistAdapter = ChecklistAdapter(
179+
activity = activity as SimpleActivity,
180+
listener = this,
181+
recyclerView = binding.checklistList,
182+
itemClick = ::toggleCompletion
183+
)
184+
binding.checklistList.adapter = checklistAdapter
185+
}
186+
187+
checklistAdapter.submitList(items.toList())
188+
}
189+
190+
private fun toggleCompletion(any: Any) {
191+
val item = any as ChecklistItem
192+
val index = items.indexOf(item)
193+
if (index != -1) {
194+
items[index] = item.copy(isDone = !item.isDone)
195+
saveNote {
196+
loadNoteById(noteId)
197+
}
191198
}
192199
}
193200

194-
private fun saveNote(refreshIndex: Int = -1, callback: () -> Unit = {}) {
201+
private fun saveNote(callback: () -> Unit = {}) {
195202
if (note == null) {
196203
return
197204
}
@@ -205,12 +212,6 @@ class ChecklistFragment : NoteFragment(), ChecklistItemsListener {
205212
}
206213

207214
if (note != null) {
208-
if (refreshIndex != -1) {
209-
binding.checklistList.post {
210-
binding.checklistList.adapter?.notifyItemChanged(refreshIndex)
211-
}
212-
}
213-
214215
note!!.value = getChecklistItems()
215216

216217
ensureBackgroundThread {
@@ -237,7 +238,8 @@ class ChecklistFragment : NoteFragment(), ChecklistItemsListener {
237238

238239
fun getChecklistItems() = Gson().toJson(items)
239240

240-
override fun saveChecklist(callback: () -> Unit) {
241+
override fun saveChecklist(updatedItems: List<ChecklistItem>, callback: () -> Unit) {
242+
items = updatedItems.toMutableList()
241243
saveNote(callback = callback)
242244
}
243245

app/src/main/kotlin/org/fossify/notes/helpers/Config.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class Config(context: Context) : BaseConfig(context) {
7676
set(lastCreatedNoteType) = prefs.edit().putInt(LAST_CREATED_NOTE_TYPE, lastCreatedNoteType).apply()
7777

7878
var moveDoneChecklistItems: Boolean
79-
get() = prefs.getBoolean(MOVE_DONE_CHECKLIST_ITEMS, true)
79+
get() = prefs.getBoolean(MOVE_DONE_CHECKLIST_ITEMS, false)
8080
set(moveDoneChecklistItems) = prefs.edit().putBoolean(MOVE_DONE_CHECKLIST_ITEMS, moveDoneChecklistItems).apply()
8181

8282
fun getTextGravity() = when (gravity) {
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package org.fossify.notes.interfaces
22

3+
import org.fossify.notes.models.ChecklistItem
4+
35
interface ChecklistItemsListener {
46
fun refreshItems()
57

6-
fun saveChecklist(callback: () -> Unit = {})
8+
fun saveChecklist(updatedItems: List<ChecklistItem>, callback: () -> Unit = {})
79
}

app/src/main/kotlin/org/fossify/notes/models/ChecklistItem.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import org.fossify.notes.helpers.CollatorBasedComparator
99
data class ChecklistItem(
1010
val id: Int,
1111
val dateCreated: Long = 0L,
12-
var title: String,
13-
var isDone: Boolean
12+
val title: String,
13+
val isDone: Boolean
1414
) : Comparable<ChecklistItem> {
1515

1616
companion object {

0 commit comments

Comments
 (0)