From 416bcc25f87d3fdf5b64e81f9fab215dd2282835 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Tue, 3 Mar 2026 22:53:01 +0600 Subject: [PATCH] fix(source): localize Source labels and parsing via string resources Replace Source enum string formatting/parsing logic with resource ID mapping so source labels are fully localized and no longer depend on hardcoded English values. Move string resolution to UI call sites, update category-to-list navigation to pass @StringRes IDs, and add system_app translations for English, French, German, Spanish, and Italian. Also update SourceTest to validate resource-based toString/fromString behavior. --- .../foundation/e/apps/data/enums/Source.kt | 31 +++++++------------ .../ui/application/ApplicationFragment.kt | 2 +- .../ApplicationListFragment.kt | 4 ++- .../ApplicationListRVAdapter.kt | 2 +- .../ApplicationListViewModel.kt | 5 +-- .../categories/model/CategoriesRVAdapter.kt | 12 ++++++- .../res/navigation/navigation_resource.xml | 4 +-- app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values-it/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + .../e/apps/data/enums/SourceTest.kt | 27 ++++++++++------ 13 files changed, 54 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/data/enums/Source.kt b/app/src/main/java/foundation/e/apps/data/enums/Source.kt index a62bf8b39..fb1d51a1b 100644 --- a/app/src/main/java/foundation/e/apps/data/enums/Source.kt +++ b/app/src/main/java/foundation/e/apps/data/enums/Source.kt @@ -17,29 +17,20 @@ package foundation.e.apps.data.enums -enum class Source { - OPEN_SOURCE, - PWA, - SYSTEM_APP, - PLAY_STORE; +import androidx.annotation.StringRes +import foundation.e.apps.R - override fun toString(): String { - return when (this) { - PLAY_STORE -> "" - else -> name.lowercase() - .split("_") - .joinToString(" ") { it.replaceFirstChar(Char::uppercase) } - } - } +enum class Source(@param:StringRes val stringResId: Int?) { + OPEN_SOURCE(R.string.open_source), + PWA(R.string.pwa), + SYSTEM_APP(R.string.system_app), + PLAY_STORE(null); + + fun toString(getString: (Int) -> String) = stringResId?.let(getString) ?: "" companion object { - fun fromString(source: String): Source { - return when (source) { - "Open Source" -> OPEN_SOURCE - "PWA" -> PWA - "SYSTEM_APP" -> SYSTEM_APP - else -> PLAY_STORE - } + fun fromStringResId(@StringRes source: Int): Source { + return entries.find { it.stringResId == source } ?: PLAY_STORE } } } diff --git a/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt b/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt index 0f1606afa..3148ea144 100644 --- a/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt +++ b/app/src/main/java/foundation/e/apps/ui/application/ApplicationFragment.kt @@ -447,7 +447,7 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { val source = if (isFdroidDeepLink) Source.OPEN_SOURCE else args.source if (source == Source.OPEN_SOURCE || source == Source.PWA) { sourceTag.visibility = View.VISIBLE - sourceTag.text = it.source.toString() + sourceTag.text = it.source.toString(::getString) } appIcon.load(it.iconUrl) } diff --git a/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListFragment.kt b/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListFragment.kt index d59988a29..786ea7760 100644 --- a/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListFragment.kt +++ b/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListFragment.kt @@ -34,6 +34,7 @@ import foundation.e.apps.R import foundation.e.apps.data.ResultSupreme import foundation.e.apps.data.application.ApplicationInstaller import foundation.e.apps.data.application.data.Application +import foundation.e.apps.data.enums.Source import foundation.e.apps.data.enums.Status import foundation.e.apps.data.install.download.data.DownloadProgress import foundation.e.apps.data.install.pkg.AppLoungePackageManager @@ -228,8 +229,9 @@ class ApplicationListFragment : * Issue: https://gitlab.e.foundation/e/os/backlog/-/issues/478 */ showLoadingUI() + val sourceType = Source.fromStringResId(args.source) viewModel.loadList(args.category, args.source) - if (args.source != "Open Source" && args.source != "PWA") { + if (sourceType != Source.OPEN_SOURCE && sourceType != Source.PWA) { /* * For Play store apps we try to load more apps on reaching end of list. * Source: https://stackoverflow.com/a/46342525 diff --git a/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListRVAdapter.kt b/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListRVAdapter.kt index a803cc483..596a463d0 100644 --- a/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListRVAdapter.kt +++ b/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListRVAdapter.kt @@ -217,7 +217,7 @@ class ApplicationListRVAdapter( private fun ApplicationListItemBinding.updateSourceTag(searchApp: Application) { sourceTag.visibility = View.INVISIBLE - val tag = searchApp.source.toString() + val tag = searchApp.source.toString(root.context::getString) if (tag.isNotBlank()) { sourceTag.text = tag sourceTag.visibility = View.VISIBLE diff --git a/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListViewModel.kt b/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListViewModel.kt index 3f91723a9..c20c6cc1a 100644 --- a/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListViewModel.kt +++ b/app/src/main/java/foundation/e/apps/ui/applicationlist/ApplicationListViewModel.kt @@ -18,6 +18,7 @@ package foundation.e.apps.ui.applicationlist +import androidx.annotation.StringRes import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -45,11 +46,11 @@ class ApplicationListViewModel @Inject constructor( private var nextPageUrl: String? = null - fun loadList(category: String, source: String) { + fun loadList(category: String, @StringRes sourceResourceId: Int) { if (isLoading) { return } - val sourceType = Source.fromString(source) + val sourceType = Source.fromStringResId(sourceResourceId) val isCleanApk = sourceType != Source.PLAY_STORE viewModelScope.launch(Dispatchers.IO) { diff --git a/app/src/main/java/foundation/e/apps/ui/categories/model/CategoriesRVAdapter.kt b/app/src/main/java/foundation/e/apps/ui/categories/model/CategoriesRVAdapter.kt index 541af026d..f4c304efb 100644 --- a/app/src/main/java/foundation/e/apps/ui/categories/model/CategoriesRVAdapter.kt +++ b/app/src/main/java/foundation/e/apps/ui/categories/model/CategoriesRVAdapter.kt @@ -26,6 +26,8 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import coil.load import foundation.e.apps.data.application.data.Category +import foundation.e.apps.data.enums.AppTag +import foundation.e.apps.data.enums.Source import foundation.e.apps.databinding.CategoriesListItemBinding import foundation.e.apps.ui.categories.CategoriesFragmentDirections @@ -54,7 +56,7 @@ class CategoriesRVAdapter : CategoriesFragmentDirections.actionCategoriesFragmentToApplicationListFragment( oldList[position].id, oldList[position].title, - oldList[position].tag.getOperationalTag(), + getSourceStringResId(oldList[position].tag) ?: 0, oldList[position].browseUrl ) holder.itemView.findNavController().navigate(direction) @@ -84,6 +86,14 @@ class CategoriesRVAdapter : } } + private fun getSourceStringResId(tag: AppTag): Int? { + return when (tag) { + is AppTag.OpenSource -> Source.OPEN_SOURCE.stringResId + is AppTag.PWA -> Source.PWA.stringResId + is AppTag.GPlay -> Source.PLAY_STORE.stringResId + } + } + override fun getItemCount(): Int { return oldList.size } diff --git a/app/src/main/res/navigation/navigation_resource.xml b/app/src/main/res/navigation/navigation_resource.xml index 9de936fd2..00add46d0 100644 --- a/app/src/main/res/navigation/navigation_resource.xml +++ b/app/src/main/res/navigation/navigation_resource.xml @@ -167,8 +167,8 @@ app:argType="string" /> + android:defaultValue="0" + app:argType="integer" /> Kategorien-Symbol Quelloffen PWA + System-App Willkommen Mit Google-Konto anmelden Wähle aus, wie du dich anmeldest diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index f9929ad9d..38a55eadb 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -48,6 +48,7 @@ Juegos Código abierto PWA + Aplicación del sistema Bienvenido Iniciar sesión con cuenta de Google Elige cómo iniciar sesión diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 8cef795ad..7b07b05b7 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -58,6 +58,7 @@ Jeux Open Source PWA + Application système Bienvenue Confidentialité Score de Confidentialité diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 0d347c337..f10320473 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -45,6 +45,7 @@ Icona Categorie Open Source PWA + App di sistema Benvenuto Ti consigliamo di creare un account Google dedicato per App Lounge e di accedere con quello. Questo offre il miglior equilibrio tra privacy e praticità. In alternativa, puoi utilizzare la Modalità Anonima. Accedi con account Google diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 801e2ceb4..638b495ea 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -50,6 +50,7 @@ Category Icon Open Source PWA + System app Welcome We recommend creating and then signing in below with a dedicated Google account for App Lounge. This offers the best balance between privacy and convenience. Alternatively, you can use Anonymous mode. diff --git a/app/src/test/java/foundation/e/apps/data/enums/SourceTest.kt b/app/src/test/java/foundation/e/apps/data/enums/SourceTest.kt index 439a5c3b1..33156a79e 100644 --- a/app/src/test/java/foundation/e/apps/data/enums/SourceTest.kt +++ b/app/src/test/java/foundation/e/apps/data/enums/SourceTest.kt @@ -1,23 +1,30 @@ package foundation.e.apps.data.enums import com.google.common.truth.Truth.assertThat +import foundation.e.apps.R import org.junit.Test class SourceTest { @Test - fun toStringFormatsNicely() { - assertThat(Source.OPEN_SOURCE.toString()).isEqualTo("Open Source") - assertThat(Source.PWA.toString()).isEqualTo("Pwa") - assertThat(Source.SYSTEM_APP.toString()).isEqualTo("System App") - assertThat(Source.PLAY_STORE.toString()).isEqualTo("") + fun toStringUsesLocalizedResource() { + val strings = mapOf( + R.string.open_source to "Open Source", + R.string.pwa to "PWA", + R.string.system_app to "System app" + ) + + assertThat(Source.OPEN_SOURCE.toString(strings::getValue)).isEqualTo("Open Source") + assertThat(Source.PWA.toString(strings::getValue)).isEqualTo("PWA") + assertThat(Source.SYSTEM_APP.toString(strings::getValue)).isEqualTo("System app") + assertThat(Source.PLAY_STORE.toString(strings::getValue)).isEqualTo("") } @Test - fun fromStringParsesKnownValues() { - assertThat(Source.fromString("Open Source")).isEqualTo(Source.OPEN_SOURCE) - assertThat(Source.fromString("PWA")).isEqualTo(Source.PWA) - assertThat(Source.fromString("SYSTEM_APP")).isEqualTo(Source.SYSTEM_APP) - assertThat(Source.fromString("unknown")).isEqualTo(Source.PLAY_STORE) + fun fromStringParsesKnownResourceIds() { + assertThat(Source.fromStringResId(R.string.open_source)).isEqualTo(Source.OPEN_SOURCE) + assertThat(Source.fromStringResId(R.string.pwa)).isEqualTo(Source.PWA) + assertThat(Source.fromStringResId(R.string.system_app)).isEqualTo(Source.SYSTEM_APP) + assertThat(Source.fromStringResId(R.string.app_name)).isEqualTo(Source.PLAY_STORE) } } -- GitLab