Skip to content

Commit 9f99b7b

Browse files
committed
Upload file
1 parent 2841b5b commit 9f99b7b

5 files changed

Lines changed: 455 additions & 274 deletions

File tree

common/src/main/java/com/omarea/common/ui/AdapterAppChooser.kt

Lines changed: 87 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -11,245 +11,168 @@ import kotlinx.coroutines.*
1111
import java.util.*
1212

1313
class AdapterAppChooser(
14-
private val context: Context,
15-
private var apps: ArrayList<AppInfo>,
16-
private val multiple: Boolean
14+
private val context: Context,
15+
private var apps: ArrayList<AppInfo>,
16+
private val multiple: Boolean
1717
) : BaseAdapter(), Filterable {
18+
1819
interface SelectStateListener {
1920
fun onSelectChange(selected: List<AppInfo>)
2021
}
2122

2223
open class AppInfo {
23-
var appName: String = ""
24-
var packageName: String = ""
25-
26-
// 是否未找到此应用
24+
var appName: String? = null
25+
var packageName: String? = null
2726
var notFound: Boolean = false
2827
var selected: Boolean = false
2928
}
3029

3130
private var selectStateListener: SelectStateListener? = null
3231
private var filter: Filter? = null
32+
3333
internal var filterApps: ArrayList<AppInfo> = apps
3434
private val mLock = Any()
3535

36-
private class ArrayFilter(private var adapter: AdapterAppChooser) : Filter() {
37-
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
38-
adapter.filterApps = results!!.values as ArrayList<AppInfo>
39-
if (results.count > 0) {
40-
adapter.notifyDataSetChanged()
41-
} else {
42-
adapter.notifyDataSetInvalidated()
43-
}
44-
}
45-
46-
private fun searchStr(valueText: String, keyword: String): Boolean {
47-
// First match against the whole, non-splitted value
48-
if (valueText.contains(keyword)) {
49-
return true
50-
} else {
51-
val words = valueText.split(" ".toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()
52-
val wordCount = words.size
53-
54-
// Start at index 0, in case valueText starts with space(s)
55-
for (k in 0 until wordCount) {
56-
if (words[k].contains(keyword)) {
57-
return true
58-
}
59-
}
60-
}
61-
return false
62-
}
36+
private class ArrayFilter(private val adapter: AdapterAppChooser) : Filter() {
6337

6438
override fun performFiltering(constraint: CharSequence?): FilterResults {
6539
val results = FilterResults()
66-
val prefix: String = constraint?.toString() ?: ""
40+
val prefix = constraint?.toString()?.lowercase() ?: ""
6741

6842
if (prefix.isEmpty()) {
69-
val list: ArrayList<AppInfo>
7043
synchronized(adapter.mLock) {
71-
list = ArrayList<AppInfo>(adapter.apps)
44+
results.values = ArrayList(adapter.apps)
45+
results.count = adapter.apps.size
7246
}
73-
results.values = list
74-
results.count = list.size
75-
} else {
76-
val prefixString = prefix.lowercase()
47+
return results
48+
}
7749

78-
val values: ArrayList<AppInfo>
79-
synchronized(adapter.mLock) {
80-
values = ArrayList<AppInfo>(adapter.apps)
81-
}
82-
val selected = adapter.getSelectedItems()
83-
84-
val count = values.size
85-
val newValues = ArrayList<AppInfo>()
86-
87-
for (i in 0 until count) {
88-
val value = values[i]
89-
if (selected.contains(value)) {
90-
newValues.add(value)
91-
} else {
92-
val labelText = value.appName.lowercase()
93-
val valueText = value.packageName.lowercase()
94-
if (searchStr(labelText, prefixString)) {
95-
newValues.add(value)
96-
} else if (searchStr(valueText, prefixString)) {
97-
newValues.add(value)
98-
}
99-
}
50+
val selected = adapter.getSelectedItems()
51+
val newValues = ArrayList<AppInfo>()
52+
53+
for (item in adapter.apps) {
54+
if (selected.contains(item)) {
55+
newValues.add(item)
56+
continue
10057
}
10158

102-
results.values = newValues
103-
results.count = newValues.size
59+
val name = item.appName?.lowercase() ?: ""
60+
val pkg = item.packageName?.lowercase() ?: ""
61+
62+
if (name.contains(prefix) || pkg.contains(prefix)) {
63+
newValues.add(item)
64+
}
10465
}
10566

67+
results.values = newValues
68+
results.count = newValues.size
10669
return results
10770
}
71+
72+
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
73+
if (results?.values is ArrayList<*>) {
74+
@Suppress("UNCHECKED_CAST")
75+
adapter.filterApps = results.values as ArrayList<AppInfo>
76+
adapter.notifyDataSetChanged()
77+
}
78+
}
10879
}
10980

11081
override fun getFilter(): Filter {
111-
if (filter == null) {
112-
filter = ArrayFilter(this)
113-
}
82+
if (filter == null) filter = ArrayFilter(this)
11483
return filter!!
11584
}
11685

11786
private val iconCaches = LruCache<String, Drawable>(100)
11887

119-
init {
120-
filterApps.sortBy { !it.selected }
121-
}
88+
override fun getCount(): Int = filterApps.size
12289

123-
override fun getCount(): Int {
124-
return filterApps.size
125-
}
90+
override fun getItem(position: Int): AppInfo = filterApps[position]
12691

127-
override fun getItem(position: Int): AppInfo {
128-
return filterApps[position]
129-
}
92+
override fun getItemId(position: Int): Long = position.toLong()
13093

131-
override fun getItemId(position: Int): Long {
132-
return position.toLong()
94+
override fun getView(position: Int, view: View?, parent: ViewGroup): View {
95+
val convertView = view ?: View.inflate(
96+
context,
97+
if (multiple) R.layout.app_multiple_chooser_item
98+
else R.layout.app_single_chooser_item,
99+
null
100+
)
101+
102+
updateRow(position, convertView)
103+
return convertView
133104
}
134105

135106
private fun loadIcon(app: AppInfo): Deferred<Drawable?> {
136107
return GlobalScope.async(Dispatchers.IO) {
137-
val packageName = app.packageName
138-
val icon: Drawable? = iconCaches.get(packageName)
139-
if (icon == null && !app.notFound) {
108+
val pkg = app.packageName ?: return@async null
109+
val cached = iconCaches.get(pkg)
110+
if (cached != null) return@async cached
111+
112+
if (!app.notFound) {
140113
try {
141-
val installInfo = context.packageManager.getPackageInfo(packageName, 0)
142-
iconCaches.put(
143-
packageName,
144-
installInfo.applicationInfo?.loadIcon(context.packageManager)
145-
)
114+
val info = context.packageManager.getPackageInfo(pkg, 0)
115+
val icon = info.applicationInfo?.loadIcon(context.packageManager)
116+
if (icon != null) iconCaches.put(pkg, icon)
146117
} catch (_: Exception) {
147118
app.notFound = true
148-
} finally {
149119
}
150-
return@async iconCaches.get(packageName)
151-
} else {
152-
return@async icon
153120
}
154-
}
155-
}
156-
157-
override fun getView(position: Int, view: View?, parent: ViewGroup): View {
158-
var convertView = view
159-
if (convertView == null) {
160-
convertView = View.inflate(context, if (multiple) {
161-
R.layout.app_multiple_chooser_item
162-
} else {
163-
R.layout.app_single_chooser_item
164-
}, null)
165-
}
166-
updateRow(position, convertView!!)
167-
return convertView
168-
}
169-
170-
fun updateRow(position: Int, listView: OverScrollGridView, AppInfo: AppInfo) {
171-
try {
172-
val visibleFirstPosi = listView.firstVisiblePosition
173-
val visibleLastPosi = listView.lastVisiblePosition
174-
175-
if (position in visibleFirstPosi..visibleLastPosi) {
176-
filterApps[position] = AppInfo
177-
val view = listView.getChildAt(position - visibleFirstPosi)
178-
updateRow(position, view)
179-
}
180-
} catch (_: Exception) {
121+
iconCaches.get(pkg)
181122
}
182123
}
183124

184125
fun updateRow(position: Int, convertView: View) {
185126
val item = getItem(position)
186127

187-
val viewHolder = if (convertView.tag != null) {
188-
convertView.tag as ViewHolder
189-
} else {
190-
ViewHolder().apply {
191-
itemTitle = convertView.findViewById(R.id.ItemTitle)
192-
itemDesc = convertView.findViewById(R.id.ItemDesc)
193-
imgView = convertView.findViewById(R.id.ItemIcon)
194-
checkBox = convertView.findViewById(R.id.ItemChecBox)
195-
}
128+
val holder = (convertView.tag as? ViewHolder) ?: ViewHolder(convertView).also {
129+
convertView.tag = it
196130
}
197131

198-
val packageName = item.packageName
199-
viewHolder.packageName = packageName
132+
holder.itemTitle.text = item.appName ?: ""
133+
holder.itemDesc.text = item.packageName ?: ""
134+
holder.checkBox?.isChecked = item.selected
200135

201136
convertView.setOnClickListener {
202-
if (multiple || item.selected) {
203-
if (multiple) {
204-
item.selected = !item.selected
205-
viewHolder.checkBox?.isChecked = item.selected
206-
}
137+
if (multiple) {
138+
item.selected = !item.selected
139+
holder.checkBox?.isChecked = item.selected
207140
} else {
208-
val current = apps.find { it.selected }
209-
current?.selected = false
141+
apps.forEach { it.selected = false }
210142
item.selected = true
211143
notifyDataSetChanged()
212144
}
213145
selectStateListener?.onSelectChange(getSelectedItems())
214146
}
215147

216-
viewHolder.run {
217-
itemTitle?.text = item.appName
218-
itemDesc?.text = item.packageName
219-
checkBox?.isChecked = item.selected
220-
221-
val imgView = imgView!!
222-
imgView.tag = packageName
223-
GlobalScope.launch(Dispatchers.Main) {
224-
val icon = loadIcon(item).await()
225-
if (icon != null && imgView.tag == packageName) {
226-
imgView.setImageDrawable(icon)
227-
}
148+
val pkg = item.packageName
149+
holder.imgView.tag = pkg
150+
151+
GlobalScope.launch(Dispatchers.Main) {
152+
val icon = loadIcon(item).await()
153+
if (icon != null && holder.imgView.tag == pkg) {
154+
holder.imgView.setImageDrawable(icon)
228155
}
229156
}
230157
}
231158

232159
fun setSelectAllState(allSelected: Boolean) {
233-
apps.forEach {
234-
it.selected = allSelected
235-
}
160+
apps.forEach { it.selected = allSelected }
236161
notifyDataSetChanged()
162+
selectStateListener?.onSelectChange(getSelectedItems())
237163
}
238164

239-
fun setSelectStateListener(selectStateListener: SelectStateListener?) {
240-
this.selectStateListener = selectStateListener
241-
}
165+
fun getSelectedItems(): List<AppInfo> =
166+
apps.filter { it.selected }
242167

243-
fun getSelectedItems(): List<AppInfo> {
244-
return apps.filter { it.selected }
168+
fun setSelectStateListener(listener: SelectStateListener?) {
169+
this.selectStateListener = listener
245170
}
246171

247-
class ViewHolder {
248-
internal var packageName: String? = null
249-
250-
internal var itemTitle: TextView? = null
251-
internal var itemDesc: TextView? = null
252-
internal var imgView: ImageView? = null
253-
internal var checkBox: CompoundButton? = null
172+
class ViewHolder(view: View) {
173+
val itemTitle: TextView = view.findViewById(R.id.ItemTitle)
174+
val itemDesc: TextView = view.findViewById(R.id.ItemDesc)
175+
val imgView: ImageView = view.findViewById(R.id.ItemIcon)
176+
val checkBox: CompoundButton? = view.findViewById(R.id.ItemChecBox)
254177
}
255-
}
178+
}

0 commit comments

Comments
 (0)