Use list adapter in app drawer

This commit is contained in:
Naveen Singh
2024-07-26 15:28:02 +05:30
parent 2a3f4d910b
commit d76f9ffd78
2 changed files with 55 additions and 75 deletions

View File

@@ -1,9 +1,12 @@
package org.fossify.launcher.adapters
import android.annotation.SuppressLint
import android.graphics.drawable.Drawable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
@@ -21,78 +24,41 @@ import org.fossify.launcher.databinding.ItemLauncherLabelBinding
import org.fossify.launcher.extensions.config
import org.fossify.launcher.interfaces.AllAppsListener
import org.fossify.launcher.models.AppLauncher
import org.fossify.launcher.models.HomeScreenGridItem
class LaunchersAdapter(
val activity: SimpleActivity,
launchers: ArrayList<AppLauncher>,
val allAppsListener: AllAppsListener,
val itemClick: (Any) -> Unit
) : RecyclerView.Adapter<LaunchersAdapter.ViewHolder>(), RecyclerViewFastScroller.OnPopupTextUpdate {
) : ListAdapter<AppLauncher, LaunchersAdapter.ViewHolder>(AppLauncherDiffCallback()), RecyclerViewFastScroller.OnPopupTextUpdate {
private var textColor = activity.getProperTextColor()
private var iconPadding = 0
private var wereFreshIconsLoaded = false
private var filterQuery: String? = null
private var filteredLaunchers: List<AppLauncher> = launchers
var launchers: ArrayList<AppLauncher> = launchers
set(value) {
field = value
updateFilter()
}
init {
setHasStableIds(true)
calculateIconWidth()
}
override fun getItemId(position: Int): Long {
return getItem(position).getLauncherIdentifier().hashCode().toLong()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemLauncherLabelBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding.root)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindView(filteredLaunchers[position])
holder.bindView(getItem(position))
}
override fun getItemCount() = filteredLaunchers.size
private fun calculateIconWidth() {
val currentColumnCount = activity.config.drawerColumnCount
val iconWidth = activity.realScreenSize.x / currentColumnCount
iconPadding = (iconWidth * 0.1f).toInt()
}
fun hideIcon(item: HomeScreenGridItem) {
val itemToRemove = launchers.firstOrNull { it.getLauncherIdentifier() == item.getItemIdentifier() }
if (itemToRemove != null) {
val position = launchers.indexOfFirst { it.getLauncherIdentifier() == item.getItemIdentifier() }
val filteredPosition = filteredLaunchers.indexOfFirst { it.getLauncherIdentifier() == item.getItemIdentifier() }
launchers.removeAt(position)
updateFilter()
notifyItemRemoved(filteredPosition)
}
}
fun updateItems(newItems: ArrayList<AppLauncher>) {
val oldSum = launchers.sumOf { it.getHashToCompare() }
val newSum = newItems.sumOf { it.getHashToCompare() }
if (oldSum != newSum || !wereFreshIconsLoaded) {
launchers = newItems
notifyDataSetChanged()
wereFreshIconsLoaded = true
}
}
fun updateSearchQuery(newQuery: String?) {
if (filterQuery != newQuery) {
filterQuery = newQuery
updateFilter()
notifyDataSetChanged()
}
}
@SuppressLint("NotifyDataSetChanged")
fun updateTextColor(newTextColor: Int) {
if (newTextColor != textColor) {
textColor = newTextColor
@@ -100,10 +66,6 @@ class LaunchersAdapter(
}
}
private fun updateFilter() {
filteredLaunchers = launchers.filter { filterQuery == null || it.title.contains(filterQuery!!, ignoreCase = true) }
}
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bindView(launcher: AppLauncher): View {
val binding = ItemLauncherLabelBinding.bind(itemView)
@@ -112,7 +74,6 @@ class LaunchersAdapter(
binding.launcherLabel.setTextColor(textColor)
binding.launcherIcon.setPadding(iconPadding, iconPadding, iconPadding, 0)
// Once all images are loaded and crossfades are done, directly set drawables
if (launcher.drawable != null && binding.launcherIcon.tag == true) {
binding.launcherIcon.setImageDrawable(launcher.drawable)
} else {
@@ -127,14 +88,13 @@ class LaunchersAdapter(
.into(object : DrawableImageViewTarget(binding.launcherIcon) {
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
super.onResourceReady(resource, transition)
// Set tag to true to mark that crossfade was already done on this view
view.tag = true
}
})
}
setOnClickListener { itemClick(launcher) }
setOnLongClickListener { view ->
setOnLongClickListener {
val location = IntArray(2)
getLocationOnScreen(location)
allAppsListener.onAppLauncherLongPressed((location[0] + width / 2).toFloat(), location[1].toFloat(), launcher)
@@ -146,5 +106,13 @@ class LaunchersAdapter(
}
}
override fun onChange(position: Int) = filteredLaunchers.getOrNull(position)?.getBubbleText() ?: ""
override fun onChange(position: Int) = currentList.getOrNull(position)?.getBubbleText() ?: ""
}
private class AppLauncherDiffCallback : DiffUtil.ItemCallback<AppLauncher>() {
override fun areItemsTheSame(oldItem: AppLauncher, newItem: AppLauncher): Boolean {
return oldItem.getLauncherIdentifier().hashCode().toLong() == newItem.getLauncherIdentifier().hashCode().toLong()
}
override fun areContentsTheSame(oldItem: AppLauncher, newItem: AppLauncher) = oldItem == newItem
}

View File

@@ -26,6 +26,8 @@ class AllAppsFragment(context: Context, attributeSet: AttributeSet) : MyFragment
var ignoreTouches = false
var hasTopPadding = false
private var launchers = emptyList<AppLauncher>()
@SuppressLint("ClickableViewAccessibility")
override fun setupFragment(activity: MainActivity) {
this.activity = activity
@@ -61,7 +63,6 @@ class AllAppsFragment(context: Context, attributeSet: AttributeSet) : MyFragment
val layoutManager = binding.allAppsGrid.layoutManager as MyGridLayoutManager
layoutManager.spanCount = context.config.drawerColumnCount
val launchers = (binding.allAppsGrid.adapter as LaunchersAdapter).launchers
setupAdapter(launchers)
}
@@ -95,26 +96,27 @@ class AllAppsFragment(context: Context, attributeSet: AttributeSet) : MyFragment
return shouldIntercept
}
fun gotLaunchers(appLaunchers: ArrayList<AppLauncher>) {
val sorted = appLaunchers.sortedWith(
compareBy({
it.title.normalizeString().lowercase()
}, {
it.packageName
})
).toMutableList() as ArrayList<AppLauncher>
fun gotLaunchers(appLaunchers: List<AppLauncher>) {
launchers = appLaunchers.sortedWith(
compareBy(
{ it.title.normalizeString().lowercase() },
{ it.packageName }
)
)
setupAdapter(sorted)
setupAdapter(launchers)
}
private fun setupAdapter(launchers: ArrayList<AppLauncher>) {
private fun getAdapter() = binding.allAppsGrid.adapter as? LaunchersAdapter
private fun setupAdapter(launchers: List<AppLauncher>) {
activity?.runOnUiThread {
val layoutManager = binding.allAppsGrid.layoutManager as MyGridLayoutManager
layoutManager.spanCount = context.config.drawerColumnCount
val currAdapter = binding.allAppsGrid.adapter
if (currAdapter == null) {
LaunchersAdapter(activity!!, launchers, this) {
var adapter = getAdapter()
if (adapter == null) {
adapter = LaunchersAdapter(activity!!, this) {
activity?.launchApp((it as AppLauncher).packageName, it.activityName)
if (activity?.config?.closeAppDrawer == true) {
activity?.closeAppDrawer(delayed = true)
@@ -124,14 +126,22 @@ class AllAppsFragment(context: Context, attributeSet: AttributeSet) : MyFragment
}.apply {
binding.allAppsGrid.adapter = this
}
} else {
(currAdapter as LaunchersAdapter).updateItems(launchers)
}
adapter.submitList(launchers.toMutableList())
}
}
fun hideIcon(item: HomeScreenGridItem) {
(binding.allAppsGrid.adapter as? LaunchersAdapter)?.hideIcon(item)
val itemToRemove = launchers.firstOrNull { it.getLauncherIdentifier() == item.getItemIdentifier() }
if (itemToRemove != null) {
val position = launchers.indexOfFirst { it.getLauncherIdentifier() == item.getItemIdentifier() }
launchers = launchers.toMutableList().apply {
removeAt(position)
}
getAdapter()?.submitList(launchers)
}
}
fun setupViews(addTopPadding: Boolean = hasTopPadding) {
@@ -172,21 +182,23 @@ class AllAppsFragment(context: Context, attributeSet: AttributeSet) : MyFragment
val topPadding = if (addTopPadding) activity!!.statusBarHeight else 0
setPadding(0, topPadding, 0, 0)
background = ColorDrawable(context.getProperBackgroundColor())
(binding.allAppsGrid.adapter as? LaunchersAdapter)?.updateTextColor(context.getProperTextColor())
getAdapter()?.updateTextColor(context.getProperTextColor())
binding.searchBar.beVisibleIf(context.config.showSearchBar)
binding.searchBar.getToolbar().beGone()
binding.searchBar.updateColors()
binding.searchBar.setupMenu()
binding.searchBar.onSearchTextChangedListener = {
(binding.allAppsGrid.adapter as? LaunchersAdapter)?.updateSearchQuery(it)
showNoResultsPlaceholderIfNeeded()
binding.searchBar.onSearchTextChangedListener = { query ->
val filtered = launchers.filter { query.isEmpty() || it.title.contains(query, ignoreCase = true) }
getAdapter()?.submitList(filtered) {
showNoResultsPlaceholderIfNeeded()
}
}
}
private fun showNoResultsPlaceholderIfNeeded() {
val itemCount = binding.allAppsGrid.adapter?.itemCount
val itemCount = getAdapter()?.itemCount
binding.noResultsPlaceholder.beVisibleIf(itemCount != null && itemCount == 0)
}