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)
animations.fadeViewOut(actionMenu, 100)
textView.visibility = View.VISIBLE
}

View file

@ -1,10 +1,10 @@
package eu.ottop.yamlauncher
import android.R.color
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.LauncherActivityInfo
import android.content.pm.LauncherApps
import android.graphics.BlendMode
import android.graphics.BlendModeColorFilter
import android.graphics.Color
@ -27,7 +27,8 @@ class AppMenuAdapter(
var apps: MutableList<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>,
private val itemClickListener: OnItemClickListener,
private val shortcutListener: OnShortcutListener,
private val itemLongClickListener: OnItemLongClickListener
private val itemLongClickListener: OnItemLongClickListener,
private val launcherApps: LauncherApps
) :
RecyclerView.Adapter<AppMenuAdapter.AppViewHolder>() {
@ -151,17 +152,38 @@ class AppMenuAdapter(
}
}
val appInfo = app.first.activityInfo.applicationInfo
holder.textView.setTextColor(Color.parseColor(preferences?.getString("textColor", "#FFF3F3F3")))
holder.textView.text = sharedPreferenceManager.getAppName(activity, app.first.applicationInfo.packageName,app.second.second, holder.itemView.context.packageManager.getApplicationLabel(appInfo))
holder.editText.setText(holder.textView.text)
val appUtils = AppUtils()
var appInfo = appUtils.getAppInfo(
launcherApps,
app.first.applicationInfo.packageName,
app.second.second
)
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
holder.textView.setTextColor(Color.parseColor(preferences?.getString("textColor", "#FFF3F3F3")))
var appLabel: CharSequence = ""
appLabel = appInfo?.loadLabel(activity.packageManager) ?: "Removing..."
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
}
@ -170,9 +192,28 @@ class AppMenuAdapter(
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")
fun updateApps(newApps: List<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>) {
apps = newApps.toMutableList()
notifyDataSetChanged()
}
}

View file

@ -1,6 +1,7 @@
package eu.ottop.yamlauncher
import android.app.Activity
import android.content.pm.ApplicationInfo
import android.content.pm.LauncherActivityInfo
import android.content.pm.LauncherApps
import android.os.UserHandle
@ -10,9 +11,9 @@ class AppUtils {
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 launcherApps = activity.getSystemService(AppCompatActivity.LAUNCHER_APPS_SERVICE) as LauncherApps
for (i in launcherApps.profiles.indices) {
launcherApps.getActivityList(null, launcherApps.profiles[i]).forEach { app ->
if (!sharedPreferenceManager.isAppHidden(activity, app.applicationInfo.packageName, i) && app.applicationInfo.packageName != activity.applicationInfo.packageName) {
@ -21,7 +22,7 @@ class AppUtils {
}
}
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()
}
}
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.AlertDialog
import android.content.Context
import android.content.pm.LauncherActivityInfo
import android.content.pm.LauncherApps
import android.os.Bundle
import android.os.UserHandle
import android.text.Editable
@ -13,6 +15,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.Toast
import androidx.core.content.ContextCompat.getSystemService
import androidx.fragment.app.setFragmentResult
import androidx.preference.Preference
import androidx.recyclerview.widget.RecyclerView
@ -27,6 +30,7 @@ class GestureAppsFragment : Fragment(), GestureAppsAdapter.OnItemClickListener {
private val sharedPreferenceManager = SharedPreferenceManager()
private var stringUtils = StringUtils()
private val appUtils = AppUtils()
private lateinit var launcherApps: LauncherApps
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
@ -43,9 +47,11 @@ class GestureAppsFragment : Fragment(), GestureAppsAdapter.OnItemClickListener {
withContext(Dispatchers.Default) {
launcherApps = requireContext().getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps
adapter = GestureAppsAdapter(
requireContext(),
appUtils.getInstalledApps(activity as Activity).toMutableList(),
appUtils.getInstalledApps(activity as Activity, launcherApps).toMutableList(),
this@GestureAppsFragment
)
}
@ -93,7 +99,7 @@ class GestureAppsFragment : Fragment(), GestureAppsAdapter.OnItemClickListener {
val cleanQuery = stringUtils.cleanString(query)
val newFilteredApps = mutableListOf<Pair<LauncherActivityInfo, Pair<UserHandle, Int>>>()
val updatedApps = appUtils.getInstalledApps(requireActivity())
val updatedApps = appUtils.getInstalledApps(requireActivity(), launcherApps)
getFilteredApps(cleanQuery, newFilteredApps, updatedApps)

View file

@ -15,7 +15,6 @@ import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.UserHandle
import android.provider.MediaStore
import android.text.Editable
import android.text.TextWatcher
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_TEXT_END
import android.view.View.TEXT_ALIGNMENT_TEXT_START
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.TextClock
import android.widget.TextView
@ -37,8 +33,6 @@ import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.children
import androidx.core.view.marginLeft
@ -425,7 +419,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
private fun setupApps() {
handleListItems()
CoroutineScope(Dispatchers.Default).launch {
installedApps = appUtils.getInstalledApps(this@MainActivity)
installedApps = appUtils.getInstalledApps(this@MainActivity, launcherApps)
val newApps = installedApps.toMutableList()
setupRecyclerView(newApps)
@ -499,7 +493,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
}
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
recyclerView = findViewById(R.id.recycler_view)
withContext(Dispatchers.Main) {
@ -560,7 +554,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
val cleanQuery = stringUtils.cleanString(query)
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)
@ -625,7 +619,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
}, 100)
handler.postDelayed({
CoroutineScope(Dispatchers.Default).launch {
refreshAppMenu()
try {
withContext(Dispatchers.Main) {
@ -711,18 +705,27 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
}
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 {
val updatedApps = appUtils.getInstalledApps(this@MainActivity)
val updatedApps = appUtils.getInstalledApps(this@MainActivity, launcherApps)
println("update running")
if (!listsEqual(installedApps, updatedApps)) {
withContext(Dispatchers.Main) {
updateMenu(updatedApps)
}
installedApps = updatedApps
withContext(Dispatchers.Main) {
updateMenu(updatedApps)
}
installedApps = updatedApps
}
catch (_: UninitializedPropertyAccessException) {
}
}*/
}
@ -799,7 +802,7 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
searchView.textAlignment = View.TEXT_ALIGNMENT_VIEW_START
}
"center" -> {
searchView.textAlignment = View.TEXT_ALIGNMENT_CENTER
searchView.textAlignment = TEXT_ALIGNMENT_CENTER
}
"right" -> {
searchView.textAlignment = View.TEXT_ALIGNMENT_VIEW_END
@ -902,4 +905,91 @@ class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceCh
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
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:defaultValue="true"
android:defaultValue="false"
android:title="Swipe Left"
app:key="leftSwipe" />
<Preference
@ -136,7 +136,7 @@
<SwitchPreference
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:defaultValue="true"
android:defaultValue="false"
android:title="Swipe Right"
app:key="rightSwipe" />
<Preference