Skip to content

Commit 2a3c38a

Browse files
authored
Add auto sort checked items by checked timestamp (#923)
1 parent f734488 commit 2a3c38a

16 files changed

Lines changed: 325 additions & 65 deletions

File tree

TRANSLATIONS.md

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,34 +19,34 @@ See [Android Translations Converter](https://github.com/Crustack/android-transla
1919
<!-- translations:start -->
2020
| Language | Coverage |
2121
|----------|----------|
22-
| 🇺🇸 English | 100% (344/344) |
23-
| 🇪🇸 Catalan | 18% (65/344) |
24-
| 🇨🇿 Czech | 91% (314/344) |
25-
| 🇩🇰 Danish | 20% (69/344) |
26-
| 🇩🇪 German | 97% (336/344) |
27-
| 🇬🇷 Greek | 20% (72/344) |
28-
| 🇪🇸 Spanish | 91% (315/344) |
29-
| 🇫🇷 French | 95% (328/344) |
30-
| 🇭🇺 Hungarian | 18% (65/344) |
31-
| 🇮🇩 Indonesian | 21% (75/344) |
32-
| 🇮🇹 Italian | 84% (292/344) |
33-
| 🇯🇵 Japanese | 21% (73/344) |
34-
| 🇲🇲 Burmese | 26% (91/344) |
35-
| 🇳🇴 Norwegian Bokmål | 31% (107/344) |
36-
| 🇳🇱 Dutch | 61% (213/344) |
37-
| 🇳🇴 Norwegian Nynorsk | 31% (107/344) |
38-
| 🇵🇱 Polish | 87% (301/344) |
39-
| 🇧🇷 Portuguese (Brazil) | 90% (313/344) |
40-
| 🇵🇹 Portuguese (Portugal) | 20% (71/344) |
41-
| 🇷🇴 Romanian | 87% (302/344) |
42-
| 🇷🇺 Russian | 88% (306/344) |
43-
| 🇸🇰 Slovak | 18% (65/344) |
44-
| 🇸🇮 Slovenian | 31% (110/344) |
45-
| 🇸🇪 Swedish | 18% (63/344) |
46-
| 🇵🇭 Tagalog | 18% (65/344) |
47-
| 🇹🇷 Turkish | 21% (73/344) |
48-
| 🇺🇦 Ukrainian | 96% (332/344) |
49-
| 🇻🇳 Vietnamese | 31% (108/344) |
50-
| 🇨🇳 Chinese (Simplified) | 95% (329/344) |
51-
| 🇹🇼 Chinese (Traditional) | 85% (295/344) |
22+
| 🇺🇸 English | 100% (345/345) |
23+
| 🇪🇸 Catalan | 18% (65/345) |
24+
| 🇨🇿 Czech | 91% (314/345) |
25+
| 🇩🇰 Danish | 20% (69/345) |
26+
| 🇩🇪 German | 97% (336/345) |
27+
| 🇬🇷 Greek | 20% (72/345) |
28+
| 🇪🇸 Spanish | 91% (315/345) |
29+
| 🇫🇷 French | 95% (328/345) |
30+
| 🇭🇺 Hungarian | 18% (65/345) |
31+
| 🇮🇩 Indonesian | 21% (75/345) |
32+
| 🇮🇹 Italian | 84% (292/345) |
33+
| 🇯🇵 Japanese | 21% (73/345) |
34+
| 🇲🇲 Burmese | 26% (91/345) |
35+
| 🇳🇴 Norwegian Bokmål | 31% (107/345) |
36+
| 🇳🇱 Dutch | 61% (213/345) |
37+
| 🇳🇴 Norwegian Nynorsk | 31% (107/345) |
38+
| 🇵🇱 Polish | 87% (301/345) |
39+
| 🇧🇷 Portuguese (Brazil) | 90% (313/345) |
40+
| 🇵🇹 Portuguese (Portugal) | 20% (71/345) |
41+
| 🇷🇴 Romanian | 87% (302/345) |
42+
| 🇷🇺 Russian | 88% (306/345) |
43+
| 🇸🇰 Slovak | 18% (65/345) |
44+
| 🇸🇮 Slovenian | 31% (110/345) |
45+
| 🇸🇪 Swedish | 18% (63/345) |
46+
| 🇵🇭 Tagalog | 18% (65/345) |
47+
| 🇹🇷 Turkish | 21% (73/345) |
48+
| 🇺🇦 Ukrainian | 96% (332/345) |
49+
| 🇻🇳 Vietnamese | 31% (108/345) |
50+
| 🇨🇳 Chinese (Simplified) | 95% (329/345) |
51+
| 🇹🇼 Chinese (Traditional) | 85% (295/345) |
5252
<!-- translations:end -->

app/src/main/java/com/philkes/notallyx/data/model/Converters.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,15 @@ object Converters {
120120
val checked = jsonObject.getSafeBoolean("checked")
121121
val isChild = jsonObject.getSafeBoolean("isChild")
122122
val order = jsonObject.getSafeInt("order")
123-
ListItem(body, checked, isChild, order, mutableListOf())
123+
val checkedTimestamp = jsonObject.getSafeLong("checkedTimestamp")
124+
ListItem(
125+
body,
126+
checked,
127+
isChild,
128+
order,
129+
mutableListOf(),
130+
checkedTimestamp = checkedTimestamp,
131+
)
124132
}
125133
}
126134

@@ -134,6 +142,7 @@ object Converters {
134142
jsonObject.put("checked", item.checked)
135143
jsonObject.put("isChild", item.isChild)
136144
jsonObject.put("order", item.order)
145+
jsonObject.put("checkedTimestamp", item.checkedTimestamp)
137146
}
138147
return JSONArray(objects)
139148
}

app/src/main/java/com/philkes/notallyx/data/model/ListItem.kt

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ data class ListItem(
77
var order: Int?,
88
var children: MutableList<ListItem>,
99
var id: Int = -1,
10+
var checkedTimestamp: Long? = null,
1011
) : Cloneable {
1112

1213
public override fun clone(): Any {
@@ -18,26 +19,22 @@ data class ListItem(
1819
order,
1920
children.map { it.clone() as ListItem }.toMutableList(),
2021
id,
22+
checkedTimestamp,
2123
)
2224
}
2325

2426
override fun equals(other: Any?): Boolean {
25-
if (this == null && other == null) {
27+
if (this === other) {
2628
return true
2729
}
28-
if (this != null && other == null) {
29-
return false
30-
}
31-
if (this == null && other != null) {
32-
return false
33-
}
3430
if (other !is ListItem) {
3531
return false
3632
}
3733
return (this.body == other.body &&
3834
this.order == other.order &&
3935
this.checked == other.checked &&
40-
this.isChild == other.isChild)
36+
this.isChild == other.isChild &&
37+
this.checkedTimestamp == other.checkedTimestamp)
4138
}
4239

4340
val itemCount: Int

app/src/main/java/com/philkes/notallyx/data/model/ListItemExtensions.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,13 @@ fun ListItem.findChild(childId: Int): ListItem? {
1212

1313
fun ListItem.check(checked: Boolean, checkChildren: Boolean = true) {
1414
this.checked = checked
15+
val checkedTimestamp = if (checked) System.currentTimeMillis() else null
16+
this.checkedTimestamp = checkedTimestamp
1517
if (checkChildren) {
16-
this.children.forEach { child -> child.checked = checked }
18+
this.children.forEach { child ->
19+
child.checked = checked
20+
child.checkedTimestamp = checkedTimestamp
21+
}
1722
}
1823
}
1924

app/src/main/java/com/philkes/notallyx/presentation/activity/note/EditActivity.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,12 @@ import com.philkes.notallyx.presentation.view.note.preview.PreviewImageAdapter
7171
import com.philkes.notallyx.presentation.viewmodel.NotallyModel
7272
import com.philkes.notallyx.presentation.viewmodel.preference.DateFormat
7373
import com.philkes.notallyx.presentation.viewmodel.preference.EditAction
74-
import com.philkes.notallyx.presentation.viewmodel.preference.ListItemSort
7574
import com.philkes.notallyx.presentation.viewmodel.preference.NotallyXPreferences
7675
import com.philkes.notallyx.presentation.viewmodel.preference.NotesSortBy
7776
import com.philkes.notallyx.presentation.viewmodel.preference.displaySmallerSize
7877
import com.philkes.notallyx.presentation.viewmodel.preference.editBodySize
7978
import com.philkes.notallyx.presentation.viewmodel.preference.editTitleSize
79+
import com.philkes.notallyx.presentation.viewmodel.preference.isAutoSortChecked
8080
import com.philkes.notallyx.presentation.widget.WidgetProvider
8181
import com.philkes.notallyx.utils.FileError
8282
import com.philkes.notallyx.utils.changeStatusAndNavigationBarColor
@@ -925,9 +925,7 @@ abstract class EditActivity(private val type: Type) : LockedActivity<ActivityEdi
925925
Type.LIST -> {
926926
binding.EnterBody.visibility = GONE
927927
binding.CheckedListView.visibility =
928-
if (preferences.listItemSorting.value == ListItemSort.AUTO_SORT_BY_CHECKED)
929-
VISIBLE
930-
else GONE
928+
if (preferences.listItemSorting.value.isAutoSortChecked) VISIBLE else GONE
931929
}
932930
}
933931

app/src/main/java/com/philkes/notallyx/presentation/activity/note/EditListActivity.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ import com.philkes.notallyx.presentation.view.note.listitem.adapter.ListItemHigh
1919
import com.philkes.notallyx.presentation.view.note.listitem.adapter.ListItemVH
2020
import com.philkes.notallyx.presentation.view.note.listitem.init
2121
import com.philkes.notallyx.presentation.view.note.listitem.setItems
22-
import com.philkes.notallyx.presentation.view.note.listitem.sorting.ListItemParentSortCallback
2322
import com.philkes.notallyx.presentation.view.note.listitem.sorting.SortedItemsList
2423
import com.philkes.notallyx.presentation.view.note.listitem.splitByChecked
2524
import com.philkes.notallyx.presentation.view.note.listitem.toMutableList
2625
import com.philkes.notallyx.presentation.viewmodel.preference.NotallyXPreferences
2726
import com.philkes.notallyx.presentation.viewmodel.preference.autoSortByCheckedEnabled
27+
import com.philkes.notallyx.presentation.viewmodel.preference.callback
2828
import com.philkes.notallyx.utils.findAllOccurrences
2929
import com.philkes.notallyx.utils.indices
3030
import com.philkes.notallyx.utils.mapIndexed
@@ -260,9 +260,8 @@ class EditListActivity : EditActivity(Type.LIST) {
260260
binding.ScrollView,
261261
)
262262
itemsChecked =
263-
SortedItemsList(ListItemParentSortCallback(adapterChecked!!)).apply {
264-
setItems(checkedItems.toMutableList())
265-
}
263+
SortedItemsList(preferences.listItemSorting.value.callback(adapterChecked!!))
264+
.apply { setItems(checkedItems.toMutableList()) }
266265
adapterChecked?.setList(itemsChecked!!)
267266
binding.CheckedListView.adapter = adapterChecked
268267
} else {

app/src/main/java/com/philkes/notallyx/presentation/view/note/listitem/ListManager.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class ListManager(
6868
this.checkedAdapter = adapterChecked
6969
nextItemId = this.items.size + (this.itemsChecked?.size() ?: 0)
7070
Log.d(TAG, "initList:\n${this.items.toReadableString()}")
71-
this.itemsChecked?.let { Log.d(TAG, "itemsChecked:\n${it}") }
71+
this.itemsChecked?.let { Log.d(TAG, "itemsChecked:\n${it.toReadableString()}") }
7272
}
7373

7474
internal fun getState(selectedPos: Int? = null): ListState {
@@ -458,6 +458,7 @@ class ListManager(
458458
) {
459459
if (checked) {
460460
child.checked = true
461+
child.checkedTimestamp = System.currentTimeMillis()
461462
adapter.notifyItemChanged(position)
462463
val (_, parent) = items.findParent(child)!!
463464
parent.updateParentChecked()
@@ -466,6 +467,7 @@ class ListManager(
466467
uncheckWithAutoSort(child)
467468
} else {
468469
child.checked = false
470+
child.checkedTimestamp = null
469471
adapter.notifyItemChanged(position)
470472
checkParent(child, false)
471473
}
@@ -529,6 +531,7 @@ class ListManager(
529531
val (parentPos, parent) = items.findParent(item)!!
530532
if (parent.checked != checked) {
531533
parent.checked = checked
534+
parent.checkedTimestamp = if (checked) System.currentTimeMillis() else null
532535
adapter.notifyItemChanged(parentPos)
533536
}
534537
}

app/src/main/java/com/philkes/notallyx/presentation/view/note/listitem/adapter/ListItemVH.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import com.philkes.notallyx.presentation.view.note.listitem.ListManager
3232
import com.philkes.notallyx.presentation.view.note.listitem.firstBodyOrEmptyString
3333
import com.philkes.notallyx.presentation.viewmodel.preference.ListItemSort
3434
import com.philkes.notallyx.presentation.viewmodel.preference.editBodySize
35+
import com.philkes.notallyx.presentation.viewmodel.preference.isAutoSortChecked
3536
import com.philkes.notallyx.utils.changehistory.EditTextState
3637
import com.philkes.notallyx.utils.copyToClipBoard
3738
import com.philkes.notallyx.utils.textMaxLengthFilter
@@ -105,7 +106,7 @@ class ListItemVH(
105106
visibility =
106107
when {
107108
viewMode != NoteViewMode.EDIT -> GONE
108-
item.checked && autoSort == ListItemSort.AUTO_SORT_BY_CHECKED -> INVISIBLE
109+
item.checked && autoSort.isAutoSortChecked -> INVISIBLE
109110
else -> VISIBLE
110111
}
111112
contentDescription = "Drag$position"
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.philkes.notallyx.presentation.view.note.listitem.sorting
2+
3+
import androidx.recyclerview.widget.RecyclerView
4+
import com.philkes.notallyx.data.model.ListItem
5+
6+
/**
7+
* Sort algorithm that only sorts by [ListItem.checkedTimestamp]. A children is always below it's
8+
* parent and above parents with a lower order.
9+
*/
10+
class ListItemCheckedTimestampSortCallback(adapter: RecyclerView.Adapter<*>?) :
11+
ListItemParentSortCallback(adapter) {
12+
13+
override fun compareItems(item1: ListItem, item2: ListItem): Int {
14+
return (item2.checkedTimestamp ?: 0L).compareTo(item1.checkedTimestamp ?: 0L)
15+
}
16+
17+
override fun areContentsTheSame(oldItem: ListItem?, newItem: ListItem?): Boolean {
18+
return oldItem == newItem
19+
}
20+
21+
override fun areItemsTheSame(item1: ListItem?, item2: ListItem?): Boolean {
22+
return item1?.id == item2?.id
23+
}
24+
}

app/src/main/java/com/philkes/notallyx/presentation/view/note/listitem/sorting/ListItemParentSortCallback.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ import com.philkes.notallyx.presentation.view.note.listitem.findParent
1111
* Sort algorithm that only sorts by [ListItem.order]. A children is always below it's parent and
1212
* above parents with a lower order.
1313
*/
14-
class ListItemParentSortCallback(adapter: RecyclerView.Adapter<*>?) :
14+
open class ListItemParentSortCallback(adapter: RecyclerView.Adapter<*>?) :
1515
SortedListAdapterCallback<ListItem>(adapter) {
1616

17-
private var items: SortedList<ListItem>? = null
17+
protected var items: SortedList<ListItem>? = null
1818

1919
internal fun setItems(items: SortedList<ListItem>) {
2020
this.items = items
@@ -34,7 +34,7 @@ class ListItemParentSortCallback(adapter: RecyclerView.Adapter<*>?) :
3434
items!!.findParent(item2)!!.second
3535
}
3636
return when {
37-
item1.id == parent2.id -> compareOrder(item1, item2)
37+
item1.id == parent2.id -> compareItems(item1, item2)
3838
else -> compare(item1, parent2)
3939
}
4040
}
@@ -47,17 +47,17 @@ class ListItemParentSortCallback(adapter: RecyclerView.Adapter<*>?) :
4747
items!!.findParent(item1)!!.second
4848
}
4949
when {
50-
item2.id == parent1.id -> compareOrder(item1, item2)
50+
item2.id == parent1.id -> compareItems(item1, item2)
5151
else -> compare(parent1, item2)
5252
}
5353
}
5454
else -> {
55-
return compareOrder(item1, item2)
55+
return compareItems(item1, item2)
5656
}
5757
}
5858
}
5959

60-
private fun compareOrder(item1: ListItem, item2: ListItem): Int {
60+
protected open fun compareItems(item1: ListItem, item2: ListItem): Int {
6161
val orderCmp = item1.order!!.compareTo(item2.order!!)
6262
if (orderCmp == 0 && item1.isChildOf(item2)) {
6363
return -1 // happens when a parent with children is moved up, the children is

0 commit comments

Comments
 (0)