Fixed an issue with updating apps (and brought back old recycler updating logic tot ry out)

This commit is contained in:
ottoptj 2024-08-05 15:49:07 +03:00
commit 84e9ee2280
6 changed files with 186 additions and 36 deletions

View file

@ -61,6 +61,7 @@ class AppActionMenu {
activity.startActivity(intent) activity.startActivity(intent)
animations.fadeViewOut(actionMenu, 100) animations.fadeViewOut(actionMenu, 100)
textView.visibility = View.VISIBLE textView.visibility = View.VISIBLE
} }

View file

@ -1,10 +1,10 @@
package eu.ottop.yamlauncher package eu.ottop.yamlauncher
import android.R.color
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.content.pm.LauncherActivityInfo import android.content.pm.LauncherActivityInfo
import android.content.pm.LauncherApps
import android.graphics.BlendMode import android.graphics.BlendMode
import android.graphics.BlendModeColorFilter import android.graphics.BlendModeColorFilter
import android.graphics.Color import android.graphics.Color
@ -27,7 +27,8 @@ class AppMenuAdapter(
var apps: MutableList<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>, var apps: MutableList<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>,
private val itemClickListener: OnItemClickListener, private val itemClickListener: OnItemClickListener,
private val shortcutListener: OnShortcutListener, private val shortcutListener: OnShortcutListener,
private val itemLongClickListener: OnItemLongClickListener private val itemLongClickListener: OnItemLongClickListener,
private val launcherApps: LauncherApps
) : ) :
RecyclerView.Adapter<AppMenuAdapter.AppViewHolder>() { RecyclerView.Adapter<AppMenuAdapter.AppViewHolder>() {
@ -151,17 +152,38 @@ class AppMenuAdapter(
} }
} }
val appInfo = app.first.activityInfo.applicationInfo val appUtils = AppUtils()
holder.textView.setTextColor(Color.parseColor(preferences?.getString("textColor", "#FFF3F3F3"))) var appInfo = appUtils.getAppInfo(
holder.textView.text = sharedPreferenceManager.getAppName(activity, app.first.applicationInfo.packageName,app.second.second, holder.itemView.context.packageManager.getApplicationLabel(appInfo)) launcherApps,
holder.editText.setText(holder.textView.text) app.first.applicationInfo.packageName,
app.second.second
)
if (appInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) { holder.textView.setTextColor(Color.parseColor(preferences?.getString("textColor", "#FFF3F3F3")))
holder.actionMenuLayout.findViewById<TextView>(R.id.uninstall).visibility = View.GONE var appLabel: CharSequence = ""
} appLabel = appInfo?.loadLabel(activity.packageManager) ?: "Removing..."
else {
holder.actionMenuLayout.findViewById<TextView>(R.id.uninstall).visibility = View.VISIBLE println(appLabel)
if (appInfo != null) {
holder.textView.text = sharedPreferenceManager.getAppName(
activity,
appInfo.packageName,
app.second.second,
appLabel
)
holder.editText.setText(holder.textView.text)
if (appInfo.flags and ApplicationInfo.FLAG_SYSTEM != 0) {
holder.actionMenuLayout.findViewById<TextView>(R.id.uninstall).visibility =
View.GONE
} else {
holder.actionMenuLayout.findViewById<TextView>(R.id.uninstall).visibility =
View.VISIBLE
}
} }
else {holder.textView.text = appLabel}
holder.textView.visibility = View.VISIBLE holder.textView.visibility = View.VISIBLE
} }
@ -170,9 +192,28 @@ class AppMenuAdapter(
return apps.size return apps.size
} }
fun addApp(position: Int, app: Pair<LauncherActivityInfo, Pair<UserHandle, Int>>) {
apps.add(position, app)
}
fun removeApp(position: Int) {
apps.removeAt(position)
}
fun updateApp(position: Int, app: Pair<LauncherActivityInfo, Pair<UserHandle, Int>>) {
apps[position] = app
}
fun moveApp(position: Int, newPosition: Int) {
val app = apps.removeAt(position)
apps.add(newPosition, app)
}
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
fun updateApps(newApps: List<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>) { fun updateApps(newApps: List<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>) {
apps = newApps.toMutableList() apps = newApps.toMutableList()
notifyDataSetChanged() notifyDataSetChanged()
} }
} }

View file

@ -1,6 +1,7 @@
package eu.ottop.yamlauncher package eu.ottop.yamlauncher
import android.app.Activity import android.app.Activity
import android.content.pm.ApplicationInfo
import android.content.pm.LauncherActivityInfo import android.content.pm.LauncherActivityInfo
import android.content.pm.LauncherApps import android.content.pm.LauncherApps
import android.os.UserHandle import android.os.UserHandle
@ -10,9 +11,9 @@ class AppUtils {
private val sharedPreferenceManager = SharedPreferenceManager() private val sharedPreferenceManager = SharedPreferenceManager()
fun getInstalledApps(activity: Activity): List<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>> { fun getInstalledApps(activity: Activity, launcherApps: LauncherApps): List<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>> {
val allApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>() val allApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>()
val launcherApps = activity.getSystemService(AppCompatActivity.LAUNCHER_APPS_SERVICE) as LauncherApps
for (i in launcherApps.profiles.indices) { for (i in launcherApps.profiles.indices) {
launcherApps.getActivityList(null, launcherApps.profiles[i]).forEach { app -> launcherApps.getActivityList(null, launcherApps.profiles[i]).forEach { app ->
if (!sharedPreferenceManager.isAppHidden(activity, app.applicationInfo.packageName, i) && app.applicationInfo.packageName != activity.applicationInfo.packageName) { if (!sharedPreferenceManager.isAppHidden(activity, app.applicationInfo.packageName, i) && app.applicationInfo.packageName != activity.applicationInfo.packageName) {
@ -21,7 +22,7 @@ class AppUtils {
} }
} }
return allApps.sortedBy { return allApps.sortedBy {
sharedPreferenceManager.getAppName(activity, it.first.applicationInfo.packageName,it.second.second, activity.packageManager.getApplicationLabel(it.first.applicationInfo)).toString().lowercase() sharedPreferenceManager.getAppName(activity, it.first.applicationInfo.packageName,it.second.second, it.first.applicationInfo.loadLabel(activity.packageManager)).toString().lowercase()
} }
} }
@ -40,4 +41,15 @@ class AppUtils {
sharedPreferenceManager.getAppName(activity, it.first.applicationInfo.packageName,it.second.second, activity.packageManager.getApplicationLabel(it.first.applicationInfo)).toString().lowercase() sharedPreferenceManager.getAppName(activity, it.first.applicationInfo.packageName,it.second.second, activity.packageManager.getApplicationLabel(it.first.applicationInfo)).toString().lowercase()
} }
} }
fun getAppInfo(
launcherApps: LauncherApps,
packageName: String,
profile: Int
): ApplicationInfo? {
return launcherApps.getActivityList(
packageName, launcherApps.profiles[profile]
).firstOrNull()?.applicationInfo
}
} }

View file

@ -2,7 +2,9 @@ package eu.ottop.yamlauncher
import android.app.Activity import android.app.Activity
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Context
import android.content.pm.LauncherActivityInfo import android.content.pm.LauncherActivityInfo
import android.content.pm.LauncherApps
import android.os.Bundle import android.os.Bundle
import android.os.UserHandle import android.os.UserHandle
import android.text.Editable import android.text.Editable
@ -13,6 +15,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.EditText import android.widget.EditText
import android.widget.Toast import android.widget.Toast
import androidx.core.content.ContextCompat.getSystemService
import androidx.fragment.app.setFragmentResult import androidx.fragment.app.setFragmentResult
import androidx.preference.Preference import androidx.preference.Preference
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -27,6 +30,7 @@ class GestureAppsFragment : Fragment(), GestureAppsAdapter.OnItemClickListener {
private val sharedPreferenceManager = SharedPreferenceManager() private val sharedPreferenceManager = SharedPreferenceManager()
private var stringUtils = StringUtils() private var stringUtils = StringUtils()
private val appUtils = AppUtils() private val appUtils = AppUtils()
private lateinit var launcherApps: LauncherApps
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
@ -43,9 +47,11 @@ class GestureAppsFragment : Fragment(), GestureAppsAdapter.OnItemClickListener {
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
launcherApps = requireContext().getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
adapter = GestureAppsAdapter( adapter = GestureAppsAdapter(
requireContext(), requireContext(),
appUtils.getInstalledApps(activity as Activity).toMutableList(), appUtils.getInstalledApps(activity as Activity, launcherApps).toMutableList(),
this@GestureAppsFragment this@GestureAppsFragment
) )
} }
@ -93,7 +99,7 @@ class GestureAppsFragment : Fragment(), GestureAppsAdapter.OnItemClickListener {
val cleanQuery = stringUtils.cleanString(query) val cleanQuery = stringUtils.cleanString(query)
val newFilteredApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>() val newFilteredApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>()
val updatedApps = appUtils.getInstalledApps(requireActivity()) val updatedApps = appUtils.getInstalledApps(requireActivity(), launcherApps)
getFilteredApps(cleanQuery, newFilteredApps, updatedApps) getFilteredApps(cleanQuery, newFilteredApps, updatedApps)

View file

@ -15,7 +15,6 @@ import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.os.UserHandle import android.os.UserHandle
import android.provider.MediaStore
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.view.GestureDetector import android.view.GestureDetector
@ -25,11 +24,8 @@ import android.view.View
import android.view.View.TEXT_ALIGNMENT_CENTER import android.view.View.TEXT_ALIGNMENT_CENTER
import android.view.View.TEXT_ALIGNMENT_TEXT_END import android.view.View.TEXT_ALIGNMENT_TEXT_END
import android.view.View.TEXT_ALIGNMENT_TEXT_START import android.view.View.TEXT_ALIGNMENT_TEXT_START
import android.view.ViewGroup
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.TextClock import android.widget.TextClock
import android.widget.TextView import android.widget.TextView
@ -37,8 +33,6 @@ import android.widget.Toast
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.core.view.children import androidx.core.view.children
import androidx.core.view.marginLeft import androidx.core.view.marginLeft
@ -425,7 +419,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
private fun setupApps() { private fun setupApps() {
handleListItems() handleListItems()
CoroutineScope(Dispatchers.Default).launch { CoroutineScope(Dispatchers.Default).launch {
installedApps = appUtils.getInstalledApps(this@MainActivity) installedApps = appUtils.getInstalledApps(this@MainActivity, launcherApps)
val newApps = installedApps.toMutableList() val newApps = installedApps.toMutableList()
setupRecyclerView(newApps) setupRecyclerView(newApps)
@ -499,7 +493,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
} }
private suspend fun setupRecyclerView(newApps: MutableList<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>) { private suspend fun setupRecyclerView(newApps: MutableList<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>) {
adapter = AppMenuAdapter(this@MainActivity, newApps, this@MainActivity, this@MainActivity, this@MainActivity) adapter = AppMenuAdapter(this@MainActivity, newApps, this@MainActivity, this@MainActivity, this@MainActivity, launcherApps)
appMenuLinearLayoutManager.stackFromEnd = true appMenuLinearLayoutManager.stackFromEnd = true
recyclerView = findViewById(R.id.recycler_view) recyclerView = findViewById(R.id.recycler_view)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
@ -560,7 +554,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
val cleanQuery = stringUtils.cleanString(query) val cleanQuery = stringUtils.cleanString(query)
val newFilteredApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>() val newFilteredApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>()
val updatedApps = appUtils.getInstalledApps(this@MainActivity) val updatedApps = appUtils.getInstalledApps(this@MainActivity, launcherApps)
getFilteredApps(cleanQuery, newFilteredApps, updatedApps) getFilteredApps(cleanQuery, newFilteredApps, updatedApps)
@ -625,7 +619,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
}, 100) }, 100)
handler.postDelayed({ handler.postDelayed({
CoroutineScope(Dispatchers.Default).launch { CoroutineScope(Dispatchers.Default).launch {
refreshAppMenu()
try { try {
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
@ -711,18 +705,27 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
} }
suspend fun refreshAppMenu() { suspend fun refreshAppMenu() {
try {
val updatedApps = appUtils.getInstalledApps(this@MainActivity, launcherApps)
val changes = detectChanges(installedApps, updatedApps)
installedApps = updatedApps
withContext(Dispatchers.Main) {
applyChanges(changes, installedApps)
}
}
catch (_: UninitializedPropertyAccessException) {
}
/*
try { try {
val updatedApps = appUtils.getInstalledApps(this@MainActivity) val updatedApps = appUtils.getInstalledApps(this@MainActivity, launcherApps)
println("update running") println("update running")
if (!listsEqual(installedApps, updatedApps)) { withContext(Dispatchers.Main) {
withContext(Dispatchers.Main) { updateMenu(updatedApps)
updateMenu(updatedApps)
}
installedApps = updatedApps
} }
installedApps = updatedApps
} }
catch (_: UninitializedPropertyAccessException) { catch (_: UninitializedPropertyAccessException) {
} }*/
} }
@ -799,7 +802,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
searchView.textAlignment = View.TEXT_ALIGNMENT_VIEW_START searchView.textAlignment = View.TEXT_ALIGNMENT_VIEW_START
} }
"center" -> { "center" -> {
searchView.textAlignment = View.TEXT_ALIGNMENT_CENTER searchView.textAlignment = TEXT_ALIGNMENT_CENTER
} }
"right" -> { "right" -> {
searchView.textAlignment = View.TEXT_ALIGNMENT_VIEW_END searchView.textAlignment = View.TEXT_ALIGNMENT_VIEW_END
@ -902,4 +905,91 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
false false
} }
} }
fun detectChanges(oldList: List<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>, newList: List<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>): List<Change> {
val changes = mutableListOf<Change>()
val removalChanges = mutableListOf<Change>()
val oldSet = oldList.map { Pair(it.first.applicationInfo.packageName, it.second.second) }.toSet()
val newSet = newList.map { Pair(it.first.applicationInfo.packageName, it.second.second) }.toSet()
// Detect removals
oldList.forEachIndexed { index, oldItem ->
if (!newSet.contains(Pair(oldItem.first.applicationInfo.packageName, oldItem.second.second))) {
removalChanges.add(Change(ChangeType.REMOVE, index))
}
}
// Detect insertions
newList.forEachIndexed { index, newItem ->
if (!oldSet.contains(Pair(newItem.first.applicationInfo.packageName, newItem.second.second))) {
changes.add(Change(ChangeType.INSERT, index))
}
}
oldList.forEachIndexed { index, oldItem ->
if (newSet.contains(Pair(oldItem.first.applicationInfo.packageName, oldItem.second.second))) {
val newIndex = newList.indexOfFirst { it.first.applicationInfo.packageName == oldItem.first.applicationInfo.packageName && it.second.second == oldItem.second.second }
if (oldItem.first.componentName != newList[newIndex].first.componentName) {
changes.add(Change(ChangeType.UPDATE, index))
}
if (index != newIndex) {
changes.add(Change(ChangeType.MOVE, index))
}
}
}
changes.addAll(removalChanges.reversed())
return changes
}
@SuppressLint("NotifyDataSetChanged")
fun applyChanges(changes: List<Change>, updatedApps: List<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>) {
changes.forEach { change ->
when (change.type) {
ChangeType.INSERT -> {
insertItem(change.position, updatedApps[change.position])
}
ChangeType.REMOVE -> {
try {
removeItem(change.position)
}
catch (_: IndexOutOfBoundsException) {
}
}
ChangeType.UPDATE -> {
updateItem(change.position, updatedApps[change.position])
}
ChangeType.MOVE -> {
adapter?.updateApps(updatedApps)
adapter?.notifyDataSetChanged()
println("moved")
}
}
}
}
private fun insertItem(position: Int, app: Pair<LauncherActivityInfo, Pair<UserHandle, Int>>) {
adapter?.addApp(position, app)
adapter?.notifyItemInserted(position)
}
private fun removeItem(position: Int) {
adapter?.removeApp(position)
adapter?.notifyItemRemoved(position)
}
private fun updateItem(position: Int, app: Pair<LauncherActivityInfo, Pair<UserHandle, Int>>) {
adapter?.updateApp(position, app)
adapter?.notifyItemChanged(position)
}
}
data class Change(val type: ChangeType, val position: Int, val newPosition: Int = 0)
enum class ChangeType {
INSERT, REMOVE, UPDATE, MOVE
} }

View file

@ -123,7 +123,7 @@
<SwitchPreference <SwitchPreference
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:defaultValue="true" android:defaultValue="false"
android:title="Swipe Left" android:title="Swipe Left"
app:key="leftSwipe" /> app:key="leftSwipe" />
<Preference <Preference
@ -136,7 +136,7 @@
<SwitchPreference <SwitchPreference
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:defaultValue="true" android:defaultValue="false"
android:title="Swipe Right" android:title="Swipe Right"
app:key="rightSwipe" /> app:key="rightSwipe" />
<Preference <Preference