Loading .idea/codeStyles/continuationIndentation.xml 0 → 100644 +9 −0 Original line number Diff line number Diff line <component name="ProjectCodeStyleConfiguration"> <code_scheme name="Project" version="173"> <codeStyleSettings language="kotlin"> <indentOptions> <option name="CONTINUATION_INDENT_SIZE" value="4" /> </indentOptions> </codeStyleSettings> </code_scheme> </component> No newline at end of file app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListRVAdapter.kt +5 −4 Original line number Diff line number Diff line Loading @@ -40,17 +40,18 @@ import com.facebook.shimmer.ShimmerDrawable import com.google.android.material.button.MaterialButton import com.google.android.material.snackbar.Snackbar import foundation.e.apps.R import foundation.e.apps.data.cleanapk.CleanApkRetrofit import foundation.e.apps.data.enums.Status import foundation.e.apps.data.enums.User import foundation.e.apps.data.application.ApplicationInstaller import foundation.e.apps.data.application.data.Application import foundation.e.apps.data.cleanapk.CleanApkRetrofit import foundation.e.apps.data.enums.Source import foundation.e.apps.data.enums.Status import foundation.e.apps.data.enums.User import foundation.e.apps.databinding.ApplicationListItemBinding import foundation.e.apps.install.pkg.InstallerService import foundation.e.apps.ui.AppInfoFetchViewModel import foundation.e.apps.ui.MainActivityViewModel import foundation.e.apps.ui.PrivacyInfoViewModel import foundation.e.apps.ui.applicationlist.diffUtils.ConciseAppDiffUtils import foundation.e.apps.ui.search.SearchFragmentDirections import foundation.e.apps.ui.updates.UpdatesFragmentDirections import foundation.e.apps.utils.disableInstallButton Loading @@ -67,7 +68,7 @@ class ApplicationListRVAdapter( private val currentDestinationId: Int, private var lifecycleOwner: LifecycleOwner?, private var paidAppHandler: ((Application) -> Unit)? = null ) : ListAdapter<Application, ApplicationListRVAdapter.ViewHolder>(ApplicationDiffUtil()) { ) : ListAdapter<Application, ApplicationListRVAdapter.ViewHolder>(ConciseAppDiffUtils()) { private var optionalCategory = "" Loading app/src/main/java/foundation/e/apps/ui/applicationlist/diffUtils/ConciseAppDiffUtils.kt 0 → 100644 +117 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 e Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ package foundation.e.apps.ui.applicationlist.diffUtils import androidx.recyclerview.widget.DiffUtil import foundation.e.apps.BuildConfig import foundation.e.apps.data.application.data.Application import timber.log.Timber class ConciseAppDiffUtils : DiffUtil.ItemCallback<Application>() { companion object { private val PERFORMANCE_DEBUGGING = BuildConfig.DEBUG private const val TAG = "ConciseAppDiffUtils" } override fun areItemsTheSame(oldItem: Application, newItem: Application): Boolean { /* * #Application._id is based on App.id which is (unimplemented/default) hashCode of the App * class we care about package name and it's source to define if the item is same. */ val isSame = oldItem.package_name == newItem.package_name && oldItem.source.ordinal == newItem.source.ordinal if (PERFORMANCE_DEBUGGING && !isSame) { val oldInfo = "Old(pkg=${oldItem.package_name}, src=${oldItem.source})" val newInfo = "New(pkg=${newItem.package_name}, src=${newItem.source})" Timber.tag(TAG).d("item aren't same : $oldInfo vs $newInfo") } return isSame } override fun areContentsTheSame(oldItem: Application, newItem: Application): Boolean { /* * most of the properties in the Application is val * so they won't change the same way var would * and in search screen we don't care about most fields * like a version changes should not be considered as a * significant changes to re render the item */ val areAllPropsSame = oldItem.name == newItem.name && oldItem.author == newItem.author && oldItem.package_name == newItem.package_name && oldItem.category == newItem.category && oldItem.licence == newItem.licence && oldItem.icon_image_path == newItem.icon_image_path && oldItem.description == newItem.description && oldItem.isPurchased == newItem.isPurchased && oldItem.isPlaceHolder == newItem.isPlaceHolder && oldItem.ratings.usageQualityScore == newItem.ratings.usageQualityScore && oldItem.status.ordinal == newItem.status.ordinal if (PERFORMANCE_DEBUGGING && !areAllPropsSame) { logContentChanged(oldItem, newItem) } return areAllPropsSame } private fun logContentChanged(oldItem: Application, newItem: Application) { val diff = StringBuilder("contents are not the same for ${oldItem.package_name}:\n") if (oldItem.name != newItem.name) { diff.append(" name: '${oldItem.name}' vs '${newItem.name}'\n") } if (oldItem.author != newItem.author) { diff.append(" author: '${oldItem.author}' vs '${newItem.author}'\n") } if (oldItem.category != newItem.category) { diff.append(" category: '${oldItem.category}' vs '${newItem.category}'\n") } if (oldItem.description != newItem.description) { diff.append(" description: (changed)\n") // descriptions might be very long } if (oldItem.icon_image_path != newItem.icon_image_path) { val oldIcon = oldItem.icon_image_path val newIcon = newItem.icon_image_path diff.append(" icon_image_path: '$oldIcon' vs '$newIcon'\n") } if (oldItem.licence != newItem.licence) { diff.append(" licence: '${oldItem.licence}' vs '${newItem.licence}'\n") } if (oldItem.isPurchased != newItem.isPurchased) { diff.append(" isPurchased: ${oldItem.isPurchased} vs ${newItem.isPurchased}\n") } if (oldItem.isPlaceHolder != newItem.isPlaceHolder) { diff.append(" isPlaceHolder: ${oldItem.isPlaceHolder} vs ${newItem.isPlaceHolder}\n") } if (oldItem.ratings.usageQualityScore != newItem.ratings.usageQualityScore) { val oldRating = oldItem.ratings.usageQualityScore val newRating = newItem.ratings.usageQualityScore diff.append(" usageQualityScore: $oldRating vs $newRating\n") } if (oldItem.package_name != newItem.package_name) { diff.append(" package_name: '${oldItem.package_name}' vs '${newItem.package_name}'\n") } if (oldItem.status.ordinal != newItem.status.ordinal) { diff.append(" status: '${oldItem.status.name}' vs '${newItem.status.name}'\n") } Timber.tag(TAG).d(diff.toString()) } } Loading
.idea/codeStyles/continuationIndentation.xml 0 → 100644 +9 −0 Original line number Diff line number Diff line <component name="ProjectCodeStyleConfiguration"> <code_scheme name="Project" version="173"> <codeStyleSettings language="kotlin"> <indentOptions> <option name="CONTINUATION_INDENT_SIZE" value="4" /> </indentOptions> </codeStyleSettings> </code_scheme> </component> No newline at end of file
app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListRVAdapter.kt +5 −4 Original line number Diff line number Diff line Loading @@ -40,17 +40,18 @@ import com.facebook.shimmer.ShimmerDrawable import com.google.android.material.button.MaterialButton import com.google.android.material.snackbar.Snackbar import foundation.e.apps.R import foundation.e.apps.data.cleanapk.CleanApkRetrofit import foundation.e.apps.data.enums.Status import foundation.e.apps.data.enums.User import foundation.e.apps.data.application.ApplicationInstaller import foundation.e.apps.data.application.data.Application import foundation.e.apps.data.cleanapk.CleanApkRetrofit import foundation.e.apps.data.enums.Source import foundation.e.apps.data.enums.Status import foundation.e.apps.data.enums.User import foundation.e.apps.databinding.ApplicationListItemBinding import foundation.e.apps.install.pkg.InstallerService import foundation.e.apps.ui.AppInfoFetchViewModel import foundation.e.apps.ui.MainActivityViewModel import foundation.e.apps.ui.PrivacyInfoViewModel import foundation.e.apps.ui.applicationlist.diffUtils.ConciseAppDiffUtils import foundation.e.apps.ui.search.SearchFragmentDirections import foundation.e.apps.ui.updates.UpdatesFragmentDirections import foundation.e.apps.utils.disableInstallButton Loading @@ -67,7 +68,7 @@ class ApplicationListRVAdapter( private val currentDestinationId: Int, private var lifecycleOwner: LifecycleOwner?, private var paidAppHandler: ((Application) -> Unit)? = null ) : ListAdapter<Application, ApplicationListRVAdapter.ViewHolder>(ApplicationDiffUtil()) { ) : ListAdapter<Application, ApplicationListRVAdapter.ViewHolder>(ConciseAppDiffUtils()) { private var optionalCategory = "" Loading
app/src/main/java/foundation/e/apps/ui/applicationlist/diffUtils/ConciseAppDiffUtils.kt 0 → 100644 +117 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 e Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ package foundation.e.apps.ui.applicationlist.diffUtils import androidx.recyclerview.widget.DiffUtil import foundation.e.apps.BuildConfig import foundation.e.apps.data.application.data.Application import timber.log.Timber class ConciseAppDiffUtils : DiffUtil.ItemCallback<Application>() { companion object { private val PERFORMANCE_DEBUGGING = BuildConfig.DEBUG private const val TAG = "ConciseAppDiffUtils" } override fun areItemsTheSame(oldItem: Application, newItem: Application): Boolean { /* * #Application._id is based on App.id which is (unimplemented/default) hashCode of the App * class we care about package name and it's source to define if the item is same. */ val isSame = oldItem.package_name == newItem.package_name && oldItem.source.ordinal == newItem.source.ordinal if (PERFORMANCE_DEBUGGING && !isSame) { val oldInfo = "Old(pkg=${oldItem.package_name}, src=${oldItem.source})" val newInfo = "New(pkg=${newItem.package_name}, src=${newItem.source})" Timber.tag(TAG).d("item aren't same : $oldInfo vs $newInfo") } return isSame } override fun areContentsTheSame(oldItem: Application, newItem: Application): Boolean { /* * most of the properties in the Application is val * so they won't change the same way var would * and in search screen we don't care about most fields * like a version changes should not be considered as a * significant changes to re render the item */ val areAllPropsSame = oldItem.name == newItem.name && oldItem.author == newItem.author && oldItem.package_name == newItem.package_name && oldItem.category == newItem.category && oldItem.licence == newItem.licence && oldItem.icon_image_path == newItem.icon_image_path && oldItem.description == newItem.description && oldItem.isPurchased == newItem.isPurchased && oldItem.isPlaceHolder == newItem.isPlaceHolder && oldItem.ratings.usageQualityScore == newItem.ratings.usageQualityScore && oldItem.status.ordinal == newItem.status.ordinal if (PERFORMANCE_DEBUGGING && !areAllPropsSame) { logContentChanged(oldItem, newItem) } return areAllPropsSame } private fun logContentChanged(oldItem: Application, newItem: Application) { val diff = StringBuilder("contents are not the same for ${oldItem.package_name}:\n") if (oldItem.name != newItem.name) { diff.append(" name: '${oldItem.name}' vs '${newItem.name}'\n") } if (oldItem.author != newItem.author) { diff.append(" author: '${oldItem.author}' vs '${newItem.author}'\n") } if (oldItem.category != newItem.category) { diff.append(" category: '${oldItem.category}' vs '${newItem.category}'\n") } if (oldItem.description != newItem.description) { diff.append(" description: (changed)\n") // descriptions might be very long } if (oldItem.icon_image_path != newItem.icon_image_path) { val oldIcon = oldItem.icon_image_path val newIcon = newItem.icon_image_path diff.append(" icon_image_path: '$oldIcon' vs '$newIcon'\n") } if (oldItem.licence != newItem.licence) { diff.append(" licence: '${oldItem.licence}' vs '${newItem.licence}'\n") } if (oldItem.isPurchased != newItem.isPurchased) { diff.append(" isPurchased: ${oldItem.isPurchased} vs ${newItem.isPurchased}\n") } if (oldItem.isPlaceHolder != newItem.isPlaceHolder) { diff.append(" isPlaceHolder: ${oldItem.isPlaceHolder} vs ${newItem.isPlaceHolder}\n") } if (oldItem.ratings.usageQualityScore != newItem.ratings.usageQualityScore) { val oldRating = oldItem.ratings.usageQualityScore val newRating = newItem.ratings.usageQualityScore diff.append(" usageQualityScore: $oldRating vs $newRating\n") } if (oldItem.package_name != newItem.package_name) { diff.append(" package_name: '${oldItem.package_name}' vs '${newItem.package_name}'\n") } if (oldItem.status.ordinal != newItem.status.ordinal) { diff.append(" status: '${oldItem.status.name}' vs '${newItem.status.name}'\n") } Timber.tag(TAG).d(diff.toString()) } }