Skip to content

Commit d6fffba

Browse files
committed
refactor: transform FlexibleAdapter with BaseDifferAdapter
1 parent c70f56c commit d6fffba

File tree

7 files changed

+86
-130
lines changed

7 files changed

+86
-130
lines changed

app/src/main/java/com/osfans/trime/data/db/ClipboardHelper.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ object ClipboardHelper :
9090

9191
suspend fun get(id: Int) = clbDao.get(id)
9292

93+
suspend fun haveUnpinned() = clbDao.haveUnpinned()
94+
9395
suspend fun getAll() = clbDao.getAll()
9496

9597
suspend fun pin(id: Int) = clbDao.updatePinned(id, true)
@@ -107,6 +109,7 @@ object ClipboardHelper :
107109
} else {
108110
clbDao.deleteAll()
109111
}
112+
updateItemCount()
110113
}
111114

112115
/**

app/src/main/java/com/osfans/trime/data/db/CollectionHelper.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ object CollectionHelper : CoroutineScope by CoroutineScope(SupervisorJob() + Dis
2525

2626
suspend fun insert(bean: DatabaseBean) = cltDao.insert(bean)
2727

28+
suspend fun haveUnpinned() = cltDao.haveUnpinned()
29+
2830
suspend fun getAll() = cltDao.getAll()
2931

3032
suspend fun pin(id: Int) = cltDao.updatePinned(id, true)

app/src/main/java/com/osfans/trime/data/db/DatabaseDao.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ interface DatabaseDao {
4848
@Query("DELETE FROM ${DatabaseBean.TABLE_NAME} WHERE NOT pinned")
4949
suspend fun deleteAllUnpinned()
5050

51-
@Query("SELECT * FROM ${DatabaseBean.TABLE_NAME}")
51+
@Query("SELECT * FROM ${DatabaseBean.TABLE_NAME} ORDER BY pinned DESC, time DESC")
5252
suspend fun getAll(): List<DatabaseBean>
5353

5454
@Query("SELECT * FROM ${DatabaseBean.TABLE_NAME} WHERE id=:id LIMIT 1")
@@ -57,6 +57,9 @@ interface DatabaseDao {
5757
@Query("SELECT * FROM ${DatabaseBean.TABLE_NAME} WHERE rowId=:rowId LIMIT 1")
5858
suspend fun get(rowId: Long): DatabaseBean?
5959

60+
@Query("SELECT EXISTS(SELECT 1 FROM ${DatabaseBean.TABLE_NAME} WHERE pinned=0)")
61+
suspend fun haveUnpinned(): Boolean
62+
6063
@Query("SELECT COUNT(*) FROM ${DatabaseBean.TABLE_NAME}")
6164
suspend fun itemCount(): Int
6265
}

app/src/main/java/com/osfans/trime/data/db/DraftHelper.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ object DraftHelper : CoroutineScope by CoroutineScope(SupervisorJob() + Dispatch
5353

5454
suspend fun get(id: Int) = dftDao.get(id)
5555

56+
suspend fun haveUnpinned() = dftDao.haveUnpinned()
57+
5658
suspend fun getAll() = dftDao.getAll()
5759

5860
suspend fun pin(id: Int) = dftDao.updatePinned(id, true)
@@ -75,6 +77,7 @@ object DraftHelper : CoroutineScope by CoroutineScope(SupervisorJob() + Dispatch
7577
} else {
7678
dftDao.deleteAll()
7779
}
80+
updateItemCount()
7881
}
7982

8083
fun onInputEventChanged() {

app/src/main/java/com/osfans/trime/ime/symbol/DbAdapter.kt

Lines changed: 26 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import com.osfans.trime.util.ShortcutUtils
1818
import kotlinx.coroutines.launch
1919

2020
class DbAdapter(
21-
private val context: Context,
21+
private val ctx: Context,
2222
private val service: TrimeInputMethodService,
2323
theme: Theme,
2424
) : FlexibleAdapter(theme) {
@@ -34,8 +34,9 @@ class DbAdapter(
3434
SymbolBoardType.CLIPBOARD -> ClipboardHelper.pin(bean.id)
3535
SymbolBoardType.COLLECTION -> CollectionHelper.pin(bean.id)
3636
SymbolBoardType.DRAFT -> DraftHelper.pin(bean.id)
37-
else -> return@launch
37+
else -> {}
3838
}
39+
refresh()
3940
}
4041
}
4142

@@ -45,8 +46,9 @@ class DbAdapter(
4546
SymbolBoardType.CLIPBOARD -> ClipboardHelper.unpin(bean.id)
4647
SymbolBoardType.COLLECTION -> CollectionHelper.unpin(bean.id)
4748
SymbolBoardType.DRAFT -> DraftHelper.unpin(bean.id)
48-
else -> return@launch
49+
else -> {}
4950
}
51+
refresh()
5052
}
5153
}
5254

@@ -56,13 +58,14 @@ class DbAdapter(
5658
SymbolBoardType.CLIPBOARD -> ClipboardHelper.delete(bean.id)
5759
SymbolBoardType.COLLECTION -> CollectionHelper.delete(bean.id)
5860
SymbolBoardType.DRAFT -> DraftHelper.delete(bean.id)
59-
else -> return@launch
61+
else -> {}
6062
}
63+
refresh()
6164
}
6265
}
6366

6467
override fun onEdit(bean: DatabaseBean) {
65-
bean.text?.let { ShortcutUtils.launchLiquidKeyboardEdit(context, type, bean.id, it) }
68+
bean.text?.let { ShortcutUtils.launchLiquidKeyboardEdit(ctx, type, bean.id, it) }
6669
}
6770

6871
override fun onCollect(bean: DatabaseBean) {
@@ -71,54 +74,34 @@ class DbAdapter(
7174

7275
// FIXME: 这个方法可能实现得比较粗糙,需要日后改进
7376
override fun onDeleteAll() {
74-
fun deleteAll() {
75-
if (beans.all { it.pinned }) {
76-
// 如果没有未置顶的条目,则删除所有已置顶的条目
77-
service.lifecycleScope.launch {
78-
when (type) {
79-
SymbolBoardType.CLIPBOARD -> ClipboardHelper.deleteAll(false)
80-
SymbolBoardType.COLLECTION -> CollectionHelper.deleteAll(false)
81-
SymbolBoardType.DRAFT -> DraftHelper.deleteAll(false)
82-
else -> return@launch
83-
}
84-
}
85-
updateBeans(emptyList())
86-
} else {
87-
// 如果有已置顶的条目,则删除所有未置顶的条目
88-
service.lifecycleScope.launch {
89-
when (type) {
90-
SymbolBoardType.CLIPBOARD -> {
91-
ClipboardHelper.deleteAll()
92-
updateBeans(ClipboardHelper.getAll())
93-
}
94-
95-
SymbolBoardType.COLLECTION -> {
96-
CollectionHelper.deleteAll()
97-
updateBeans(CollectionHelper.getAll())
98-
}
99-
100-
SymbolBoardType.DRAFT -> {
101-
DraftHelper.deleteAll()
102-
updateBeans(DraftHelper.getAll())
103-
}
104-
105-
else -> return@launch
106-
}
107-
}
108-
}
109-
}
110-
11177
val confirm =
11278
AlertDialog
11379
.Builder(context)
11480
.setTitle(R.string.delete_all)
11581
.setMessage(R.string.liquid_keyboard_ask_to_delete_all)
11682
.setPositiveButton(R.string.ok) { _, _ ->
117-
deleteAll()
83+
service.lifecycleScope.launch {
84+
when (type) {
85+
SymbolBoardType.CLIPBOARD -> ClipboardHelper.deleteAll(ClipboardHelper.haveUnpinned())
86+
SymbolBoardType.COLLECTION -> CollectionHelper.deleteAll(CollectionHelper.haveUnpinned())
87+
SymbolBoardType.DRAFT -> DraftHelper.deleteAll(DraftHelper.haveUnpinned())
88+
else -> {}
89+
}
90+
refresh()
91+
}
11892
}.setNegativeButton(R.string.cancel, null)
11993
.create()
12094
service.inputView?.showDialog(confirm)
12195
}
12296

12397
override val showCollectButton: Boolean = type != SymbolBoardType.COLLECTION
98+
99+
private suspend fun refresh() {
100+
when (type) {
101+
SymbolBoardType.CLIPBOARD -> submitList(ClipboardHelper.getAll())
102+
SymbolBoardType.COLLECTION -> submitList(CollectionHelper.getAll())
103+
SymbolBoardType.DRAFT -> submitList(DraftHelper.getAll())
104+
else -> {}
105+
}
106+
}
124107
}

app/src/main/java/com/osfans/trime/ime/symbol/FlexibleAdapter.kt

Lines changed: 46 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@
44

55
package com.osfans.trime.ime.symbol
66

7+
import android.content.Context
78
import android.os.Build
89
import android.view.ViewGroup
910
import android.widget.PopupMenu
1011
import androidx.annotation.DrawableRes
1112
import androidx.annotation.StringRes
13+
import androidx.recyclerview.widget.DiffUtil
1214
import androidx.recyclerview.widget.RecyclerView
15+
import com.chad.library.adapter4.BaseDifferAdapter
1316
import com.osfans.trime.R
1417
import com.osfans.trime.data.db.DatabaseBean
1518
import com.osfans.trime.data.theme.Theme
@@ -19,79 +22,63 @@ import kotlin.math.min
1922

2023
abstract class FlexibleAdapter(
2124
private val theme: Theme,
22-
) : RecyclerView.Adapter<FlexibleAdapter.ViewHolder>() {
23-
private val mBeans = mutableListOf<DatabaseBean>()
24-
25-
// 映射条目的 id 和其在视图中位置的关系
26-
// 以应对增删条目时 id 和其位置的相对变化
27-
// [<id, position>, ...]
28-
private val mBeansId = mutableMapOf<Int, Int>()
29-
val beans get() = mBeans
30-
31-
fun updateBeans(beans: List<DatabaseBean>) {
32-
val sorted =
33-
beans.sortedWith { b1, b2 ->
34-
when {
35-
// 如果 b1 置顶而 b2 没置顶,则 b1 比 b2 小,排前面
36-
b1.pinned && !b2.pinned -> -1
37-
// 如果 b1 没置顶而 b2 置顶,则 b1 比 b2 大,排后面
38-
!b1.pinned && b2.pinned -> 1
39-
// 如果都置顶了或都没置顶,则比较 id,id 大的排前面
40-
else -> b2.id.compareTo(b1.id)
41-
}
25+
) : BaseDifferAdapter<DatabaseBean, FlexibleAdapter.ViewHolder>(diffCallback) {
26+
companion object {
27+
private val diffCallback =
28+
object : DiffUtil.ItemCallback<DatabaseBean>() {
29+
override fun areItemsTheSame(
30+
oldItem: DatabaseBean,
31+
newItem: DatabaseBean,
32+
): Boolean = oldItem.id == newItem.id
33+
34+
override fun areContentsTheSame(
35+
oldItem: DatabaseBean,
36+
newItem: DatabaseBean,
37+
): Boolean = oldItem == newItem
4238
}
43-
val prevSize = mBeans.size
44-
mBeans.clear()
45-
notifyItemRangeRemoved(0, prevSize)
46-
mBeans.addAll(sorted)
47-
notifyItemRangeChanged(0, sorted.size)
48-
mBeansId.clear()
49-
mBeans.forEachIndexed { index: Int, (id): DatabaseBean ->
50-
mBeansId[id] = index
51-
}
52-
}
5339

54-
private fun excerptText(
55-
str: String,
56-
lines: Int = 4,
57-
chars: Int = 128,
58-
): String =
59-
buildString {
60-
val length = str.length
61-
var lineBreak = -1
62-
for (i in 1..lines) {
63-
val start = lineBreak + 1 // skip previous '\n'
64-
val excerptEnd = min(start + chars, length)
65-
lineBreak = str.indexOf('\n', start)
66-
if (lineBreak < 0) {
67-
// no line breaks remaining, substring to end of text
68-
append(str.substring(start, excerptEnd))
69-
break
70-
} else {
71-
val end = min(excerptEnd, lineBreak)
72-
// append one line exactly
73-
appendLine(str.substring(start, end))
40+
private fun excerptText(
41+
str: String,
42+
lines: Int = 4,
43+
chars: Int = 128,
44+
): String =
45+
buildString {
46+
val length = str.length
47+
var lineBreak = -1
48+
for (i in 1..lines) {
49+
val start = lineBreak + 1 // skip previous '\n'
50+
val excerptEnd = min(start + chars, length)
51+
lineBreak = str.indexOf('\n', start)
52+
if (lineBreak < 0) {
53+
// no line breaks remaining, substring to end of text
54+
append(str.substring(start, excerptEnd))
55+
break
56+
} else {
57+
val end = min(excerptEnd, lineBreak)
58+
// append one line exactly
59+
appendLine(str.substring(start, end))
60+
}
7461
}
7562
}
76-
}
77-
78-
override fun getItemCount(): Int = mBeans.size
63+
}
7964

8065
override fun onCreateViewHolder(
66+
context: Context,
8167
parent: ViewGroup,
8268
viewType: Int,
83-
): ViewHolder = ViewHolder(SimpleItemUi(parent.context, theme))
69+
): ViewHolder = ViewHolder(SimpleItemUi(context, theme))
8470

8571
class ViewHolder(
8672
val ui: SimpleItemUi,
8773
) : RecyclerView.ViewHolder(ui.root)
8874

8975
override fun onBindViewHolder(
90-
viewHolder: ViewHolder,
76+
holder: ViewHolder,
9177
position: Int,
78+
item: DatabaseBean?,
9279
) {
93-
with(viewHolder.ui) {
94-
val bean = mBeans[position]
80+
with(holder.ui) {
81+
val bean = item ?: return
9582
setItem(excerptText(bean.text ?: ""), bean.pinned)
9683
root.setOnClickListener {
9784
onPaste(bean)
@@ -119,12 +106,10 @@ abstract class FlexibleAdapter(
119106
if (bean.pinned) {
120107
menuItem(R.string.simple_key_unpin, R.drawable.ic_outline_push_pin_24) {
121108
onUnpin(bean)
122-
setPinStatus(bean.id, false)
123109
}
124110
} else {
125111
menuItem(R.string.simple_key_pin, R.drawable.ic_baseline_push_pin_24) {
126112
onPin(bean)
127-
setPinStatus(bean.id, true)
128113
}
129114
}
130115
if (showCollectButton) {
@@ -134,12 +119,9 @@ abstract class FlexibleAdapter(
134119
}
135120
menuItem(R.string.delete, R.drawable.ic_baseline_delete_24) {
136121
onDelete(bean)
137-
delete(bean.id)
138122
}
139-
if (beans.isNotEmpty()) {
140-
menuItem(R.string.delete_all, R.drawable.ic_baseline_delete_sweep_24) {
141-
onDeleteAll()
142-
}
123+
menuItem(R.string.delete_all, R.drawable.ic_baseline_delete_sweep_24) {
124+
onDeleteAll()
143125
}
144126
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
145127
menu.setForceShowIcon(true)
@@ -150,26 +132,6 @@ abstract class FlexibleAdapter(
150132
}
151133
}
152134

153-
private fun delete(id: Int) {
154-
val position = mBeansId.getValue(id)
155-
mBeans.removeAt(position)
156-
mBeansId.remove(id)
157-
for (i in position until mBeans.size) {
158-
mBeansId[mBeans[i].id] = i
159-
}
160-
notifyItemRemoved(position)
161-
}
162-
163-
private fun setPinStatus(
164-
id: Int,
165-
pinned: Boolean,
166-
) {
167-
val position = mBeansId.getValue(id)
168-
mBeans[position] = mBeans[position].copy(pinned = pinned)
169-
// 置顶会改变条目的排列顺序
170-
updateBeans(mBeans)
171-
}
172-
173135
abstract fun onPaste(bean: DatabaseBean)
174136

175137
abstract fun onPin(bean: DatabaseBean)

app/src/main/java/com/osfans/trime/ime/symbol/LiquidKeyboard.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ class LiquidKeyboard(
207207
}
208208

209209
service.lifecycleScope.launch {
210-
dbAdapter.updateBeans(data())
210+
dbAdapter.submitList(data())
211211
}
212212
}
213213

@@ -246,7 +246,7 @@ class LiquidKeyboard(
246246
if (currentBoardType == SymbolBoardType.CLIPBOARD) {
247247
Timber.v("OnClipboardUpdateListener onUpdate: update clipboard view")
248248
service.lifecycleScope.launch {
249-
dbAdapter.updateBeans(ClipboardHelper.getAll())
249+
dbAdapter.submitList(ClipboardHelper.getAll())
250250
}
251251
}
252252
}

0 commit comments

Comments
 (0)