mirror of
https://github.com/FossifyOrg/Launcher.git
synced 2026-05-19 06:09:57 -04:00
Use list adapter in app drawer
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user