From 9b82d7e6e76dcc5d12d1bdf06450c8c9679de91c Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Wed, 11 Feb 2026 21:07:45 +0600 Subject: [PATCH 01/22] refactor(searchV2): handle error states for PlayStore and CleanAPK --- .../components/SearchResultsContentTest.kt | 49 +---------- .../components/search/SearchErrorStateTest.kt | 14 +-- .../compose/components/SearchPlaceholder.kt | 36 ++++---- .../components/SearchResultsContent.kt | 88 ++++++++----------- .../components/search/SearchErrorState.kt | 47 +++++----- app/src/main/res/values-de/strings.xml | 10 +++ app/src/main/res/values-es/strings.xml | 10 +++ app/src/main/res/values-fi/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 10 +++ app/src/main/res/values-is/strings.xml | 1 + app/src/main/res/values-it/strings.xml | 10 +++ app/src/main/res/values-ja/strings.xml | 1 + app/src/main/res/values-nb-rNO/strings.xml | 1 + app/src/main/res/values-nl/strings.xml | 1 + app/src/main/res/values-pt-rBR/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values-sk/strings.xml | 1 + app/src/main/res/values-sv/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 1 + app/src/main/res/values-uk/strings.xml | 1 + app/src/main/res/values/strings.xml | 10 ++- 21 files changed, 142 insertions(+), 153 deletions(-) diff --git a/app/src/androidTest/java/foundation/e/apps/ui/compose/components/SearchResultsContentTest.kt b/app/src/androidTest/java/foundation/e/apps/ui/compose/components/SearchResultsContentTest.kt index b673259f9..5362d4036 100644 --- a/app/src/androidTest/java/foundation/e/apps/ui/compose/components/SearchResultsContentTest.kt +++ b/app/src/androidTest/java/foundation/e/apps/ui/compose/components/SearchResultsContentTest.kt @@ -204,51 +204,6 @@ class SearchResultsContentTest { composeRule.onAllNodesWithText("Open App").assertCountEquals(0) } - @Test - fun refreshError_showsRetry() { - val pagingData = PagingData.empty( - sourceLoadStates = loadStates(refresh = LoadState.Error(RuntimeException("boom"))) - ) - - renderSearchResults( - tabs = listOf(SearchTabType.OPEN_SOURCE), - selectedTab = SearchTabType.OPEN_SOURCE, - fossPagingData = pagingData, - ) - - composeRule.onNodeWithText( - composeRule.activity.getString(R.string.search_error) - ).assertIsDisplayed() - composeRule.onNodeWithText( - composeRule.activity.getString(R.string.retry) - ).assertIsDisplayed() - } - - @Test - fun appendError_showsFooterRetryWithResults() { - val pagingData = PagingData.from( - listOf(sampleApp("Loaded App")), - sourceLoadStates = loadStates( - refresh = LoadState.NotLoading(endOfPaginationReached = false), - append = LoadState.Error(RuntimeException("append boom")) - ) - ) - - renderSearchResults( - tabs = listOf(SearchTabType.OPEN_SOURCE), - selectedTab = SearchTabType.OPEN_SOURCE, - fossPagingData = pagingData, - ) - - composeRule.onNodeWithText("Loaded App").assertIsDisplayed() - composeRule.onNodeWithText( - composeRule.activity.getString(R.string.search_error) - ).assertIsDisplayed() - composeRule.onNodeWithText( - composeRule.activity.getString(R.string.retry) - ).assertIsDisplayed() - } - @Test fun emptyResults_showsPlaceholder() { val pagingData = PagingData.empty( @@ -256,7 +211,7 @@ class SearchResultsContentTest { refresh = LoadState.NotLoading(endOfPaginationReached = true) ) ) - val noAppsText = composeRule.activity.getString(R.string.no_apps_found) + val noAppsText = composeRule.activity.getString(R.string.search_empty_results_body) renderSearchResults( tabs = listOf(SearchTabType.OPEN_SOURCE), @@ -269,7 +224,7 @@ class SearchResultsContentTest { @Test fun emptyResults_resetOnNewQuery_showsRefreshLoading() { - val noAppsText = composeRule.activity.getString(R.string.no_apps_found) + val noAppsText = composeRule.activity.getString(R.string.search_empty_results_body) val emptyPagingData = PagingData.empty( sourceLoadStates = loadStates( refresh = LoadState.NotLoading(endOfPaginationReached = true) diff --git a/app/src/androidTest/java/foundation/e/apps/ui/compose/components/search/SearchErrorStateTest.kt b/app/src/androidTest/java/foundation/e/apps/ui/compose/components/search/SearchErrorStateTest.kt index 8662ae8b3..6ace263ca 100644 --- a/app/src/androidTest/java/foundation/e/apps/ui/compose/components/search/SearchErrorStateTest.kt +++ b/app/src/androidTest/java/foundation/e/apps/ui/compose/components/search/SearchErrorStateTest.kt @@ -41,16 +41,13 @@ class SearchErrorStateTest { composeRule.setContent { AppTheme(darkTheme = false) { Surface(color = MaterialTheme.colorScheme.background) { - SearchErrorState(onRetry = {}, fullScreen = true) + SearchErrorState(errorTitleStringRes = R.string.search_error_title_opensource, fullScreen = true) } } } composeRule.onNodeWithText( - composeRule.activity.getString(R.string.search_error) - ).assertIsDisplayed() - composeRule.onNodeWithText( - composeRule.activity.getString(R.string.retry) + composeRule.activity.getString(R.string.search_error_message) ).assertIsDisplayed() } @@ -59,16 +56,13 @@ class SearchErrorStateTest { composeRule.setContent { AppTheme(darkTheme = false) { Surface(color = MaterialTheme.colorScheme.background) { - SearchErrorState(onRetry = {}, fullScreen = false) + SearchErrorState(errorTitleStringRes = R.string.search_error_title_opensource, fullScreen = false) } } } composeRule.onNodeWithText( - composeRule.activity.getString(R.string.search_error) - ).assertIsDisplayed() - composeRule.onNodeWithText( - composeRule.activity.getString(R.string.retry) + composeRule.activity.getString(R.string.search_error_message) ).assertIsDisplayed() } } diff --git a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchPlaceholder.kt b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchPlaceholder.kt index 60c415be5..637406723 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchPlaceholder.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchPlaceholder.kt @@ -18,22 +18,20 @@ package foundation.e.apps.ui.compose.components -import androidx.compose.foundation.Image +import androidx.annotation.StringRes import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.colorResource -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign.Companion.Center import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -41,7 +39,7 @@ import foundation.e.apps.R import foundation.e.apps.ui.compose.theme.AppTheme @Composable -fun SearchPlaceholder(modifier: Modifier = Modifier) { +fun SearchPlaceholder(@StringRes stringResource: Int, modifier: Modifier = Modifier) { Box( modifier = modifier .fillMaxSize(), @@ -51,21 +49,23 @@ fun SearchPlaceholder(modifier: Modifier = Modifier) { horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(12.dp), ) { - Image( - painter = painterResource(id = R.drawable.ic_error_circular), - contentDescription = stringResource(id = R.string.menu_search), - contentScale = ContentScale.Fit, - modifier = Modifier - .padding(bottom = 4.dp) - .size(96.dp), - ) Text( - text = stringResource(id = R.string.no_apps_found), + text = stringResource(id = stringResource), style = MaterialTheme.typography.bodyMedium.copy( fontSize = 18.sp ), - color = colorResource(id = R.color.light_grey), - textAlign = androidx.compose.ui.text.style.TextAlign.Center, + color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.87f), + textAlign = Center, + ) + Text( + text = stringResource(R.string.search_empty_results_body), + modifier = Modifier.padding(horizontal = 32.dp), + textAlign = Center, + style = MaterialTheme.typography.bodyMedium.copy( + fontSize = 14.sp, + fontWeight = FontWeight.Normal + ), + color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.38f) ) } } @@ -75,6 +75,6 @@ fun SearchPlaceholder(modifier: Modifier = Modifier) { @Composable private fun SearchPlaceholderPreview() { AppTheme(darkTheme = true) { - SearchPlaceholder() + SearchPlaceholder(stringResource = R.string.search_empty_results_title_playstore) } } diff --git a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt index 154b4af3b..dee254cce 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt @@ -187,26 +187,34 @@ private fun SearchTabPage( installButtonStateProvider: (Application) -> InstallButtonState, modifier: Modifier = Modifier, ) { + val items: LazyPagingItems? + val emptyResultsStringResource: Int + val errorTitleStringResource: Int + when (tab) { + SearchTabType.COMMON_APPS -> { + items = playStoreItems + emptyResultsStringResource = R.string.search_empty_results_title_playstore + errorTitleStringResource = R.string.search_error_title_playstore + } + SearchTabType.OPEN_SOURCE -> { - PagingSearchResultList( - items = fossItems, - searchVersion = searchVersion, - tab = tab, - getScrollPosition = getScrollPosition, - onScrollPositionChange = onScrollPositionChange, - onItemClick = onResultClick, - onPrimaryActionClick = onPrimaryActionClick, - onShowMoreClick = onShowMoreClick, - onPrivacyClick = onPrivacyClick, - installButtonStateProvider = installButtonStateProvider, - modifier = modifier, - ) + items = fossItems + emptyResultsStringResource = R.string.search_empty_results_title_open_source + errorTitleStringResource = R.string.search_error_title_opensource } SearchTabType.PWA -> { + items = pwaItems + emptyResultsStringResource = R.string.search_empty_results_title_pwa + errorTitleStringResource = R.string.search_error_title_pwa + } + } + + when (tab) { + SearchTabType.OPEN_SOURCE, SearchTabType.PWA -> { PagingSearchResultList( - items = pwaItems, + items = items, searchVersion = searchVersion, tab = tab, getScrollPosition = getScrollPosition, @@ -216,13 +224,15 @@ private fun SearchTabPage( onShowMoreClick = onShowMoreClick, onPrivacyClick = onPrivacyClick, installButtonStateProvider = installButtonStateProvider, + emptyResultsStringResource = emptyResultsStringResource, + errorTitleStringResource = errorTitleStringResource, modifier = modifier, ) } SearchTabType.COMMON_APPS -> { PagingPlayStoreResultList( - items = playStoreItems, + items = items, searchVersion = searchVersion, getScrollPosition = getScrollPosition, onScrollPositionChange = onScrollPositionChange, @@ -231,6 +241,8 @@ private fun SearchTabPage( onShowMoreClick = onShowMoreClick, onPrivacyClick = onPrivacyClick, installButtonStateProvider = installButtonStateProvider, + emptyResultsStringResource = emptyResultsStringResource, + errorTitleStringResource = errorTitleStringResource, modifier = modifier, ) } @@ -248,6 +260,8 @@ private fun PagingPlayStoreResultList( onShowMoreClick: (Application) -> Unit, onPrivacyClick: (Application) -> Unit, installButtonStateProvider: (Application) -> InstallButtonState, + emptyResultsStringResource: Int, + errorTitleStringResource: Int, modifier: Modifier = Modifier, ) { val lazyItems = items ?: return @@ -295,11 +309,7 @@ private fun PagingPlayStoreResultList( } val initialLoadError = refreshError != null && !hasLoadedCurrentQuery.value - val showFooterError = hasLoadedCurrentQuery.value && listOf( - refreshError, - appendError, - prependError - ).any { it != null } + val isEmpty = !isRefreshing && refreshError == null && appendError == null && prependError == null && lazyItems.itemCount == 0 @@ -311,7 +321,7 @@ private fun PagingPlayStoreResultList( initialLoadError -> { SearchErrorState( - onRetry = { lazyItems.retry() }, + errorTitleStringRes = errorTitleStringResource, modifier = Modifier.fillMaxSize(), fullScreen = true, ) @@ -319,6 +329,7 @@ private fun PagingPlayStoreResultList( isEmpty -> { SearchPlaceholder( + stringResource = emptyResultsStringResource, modifier = Modifier .fillMaxWidth() .align(Alignment.Center) @@ -375,18 +386,6 @@ private fun PagingPlayStoreResultList( } } } - - if (showFooterError) { - item(key = "error_footer_play_store") { - SearchErrorState( - onRetry = { lazyItems.retry() }, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 12.dp), - fullScreen = false, - ) - } - } } } } @@ -405,6 +404,8 @@ private fun PagingSearchResultList( onShowMoreClick: (Application) -> Unit, onPrivacyClick: (Application) -> Unit, installButtonStateProvider: (Application) -> InstallButtonState, + emptyResultsStringResource: Int, + errorTitleStringResource: Int, modifier: Modifier = Modifier, ) { val lazyItems = items ?: return @@ -448,11 +449,7 @@ private fun PagingSearchResultList( } val initialLoadError = refreshError != null && !hasLoadedCurrentQuery.value - val showFooterError = hasLoadedCurrentQuery.value && listOf( - refreshError, - appendError, - prependError - ).any { it != null } + val isEmpty = !isRefreshing && refreshError == null && appendError == null && prependError == null && lazyItems.itemCount == 0 @@ -466,7 +463,7 @@ private fun PagingSearchResultList( initialLoadError -> { SearchErrorState( - onRetry = { lazyItems.retry() }, + errorTitleStringRes = errorTitleStringResource, modifier = Modifier.fillMaxSize(), fullScreen = true, ) @@ -474,6 +471,7 @@ private fun PagingSearchResultList( isEmpty -> { SearchPlaceholder( + stringResource = emptyResultsStringResource, modifier = Modifier .fillMaxWidth() .align(Alignment.Center) @@ -535,18 +533,6 @@ private fun PagingSearchResultList( } } } - - if (showFooterError) { - item(key = "error_footer") { - SearchErrorState( - onRetry = { lazyItems.retry() }, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 12.dp), - fullScreen = false, - ) - } - } } } } diff --git a/app/src/main/java/foundation/e/apps/ui/compose/components/search/SearchErrorState.kt b/app/src/main/java/foundation/e/apps/ui/compose/components/search/SearchErrorState.kt index 964253ab5..3d62653f1 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/components/search/SearchErrorState.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/components/search/SearchErrorState.kt @@ -18,28 +18,30 @@ package foundation.e.apps.ui.compose.components.search +import androidx.annotation.StringRes import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Button import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import foundation.e.apps.R import foundation.e.apps.ui.compose.theme.AppTheme @Composable fun SearchErrorState( - onRetry: () -> Unit, + @StringRes errorTitleStringRes: Int, modifier: Modifier = Modifier, fullScreen: Boolean = true, ) { @@ -49,31 +51,29 @@ fun SearchErrorState( modifier.fillMaxWidth() } - val contentPadding = if (fullScreen) { - PaddingValues(all = 24.dp) - } else { - PaddingValues(horizontal = 16.dp, vertical = 12.dp) - } - Box( modifier = containerModifier, contentAlignment = Alignment.Center ) { Column( modifier = Modifier - .fillMaxWidth() - .padding(contentPadding), + .fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(12.dp), ) { Text( - text = stringResource(id = R.string.search_error), - style = MaterialTheme.typography.bodyLarge, - color = MaterialTheme.colorScheme.onBackground, + text = stringResource(id = errorTitleStringRes), + fontSize = 18.sp, + fontWeight = FontWeight.Medium, + color = MaterialTheme.colorScheme.onPrimary, + ) + Text( + modifier = Modifier.padding(horizontal = 24.dp), + textAlign = TextAlign.Center, + text = stringResource(id = R.string.search_error_message), + fontSize = 15.sp, + color = MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.38F), ) - Button(onClick = onRetry) { - Text(text = stringResource(id = R.string.retry)) - } } } } @@ -82,14 +82,9 @@ fun SearchErrorState( @Composable private fun SearchErrorStateFullScreenPreview() { AppTheme { - SearchErrorState(onRetry = {}, fullScreen = true) - } -} - -@Preview(showBackground = true) -@Composable -private fun SearchErrorStateFooterPreview() { - AppTheme { - SearchErrorState(onRetry = {}, fullScreen = false) + SearchErrorState( + errorTitleStringRes = R.string.search_error_title_opensource, + fullScreen = true + ) } } diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 73457fec9..b3853d9c1 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -21,6 +21,15 @@ Aktualisierungen Einstellungen Keine Apps gefunden … + Diese Seite oder Ressource ist wegen Wartungsarbeiten nicht verfügbar. + Apps vorübergehend nicht verfügbar + Open Source vorübergehend nicht verfügbar + Web Apps vorübergehend nicht verfügbar + Dieser Katalog ist derzeit nicht erreichbar. Andere Apps-Quellen können weiterhin funktionieren. + Keine Ergebnisse in Apps + Keine Ergebnisse in Open Source + Keine Ergebnisse in Web Apps + Andere Apps-Quellen können Ergebnisse liefern. Bitte prüfe die anderen Tabs/deine Einstellungen. Anwendungen Spiele Kategorien-Symbol @@ -92,6 +101,7 @@ Aktualisierungen App-Aktualisierungen werden nicht automatisch installiert Auf ein unlimitiertes Netzwerk warten + Keine Verbindung Keine Verbindung möglich. Bitte überprüfe die Internetverbindung und versuche es erneut Start App-Suche diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 1cb811082..3c49d0ba6 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -37,6 +37,15 @@ Atrás Borrar búsqueda No se encontraron aplicaciones… + Esta página o recurso no está disponible por mantenimiento. + Apps temporalmente no disponibles + Open Source temporalmente no disponible + Web Apps temporalmente no disponibles + No podemos acceder a este catálogo ahora mismo. Otras fuentes de Apps pueden seguir funcionando. + Sin resultados en Apps + Sin resultados en Open Source + Sin resultados en Web Apps + Otras fuentes de Apps pueden ofrecer resultados, revisa las otras pestañas/tu configuración. Juegos Código abierto PWA @@ -96,6 +105,7 @@ Descargas Actualizaciones Las actualizaciones no se instalarán automáticamente + Sin conexión ¡No se pudo conectar! Chequea tu conexión a internet e inténtalo de nuevo Esperando una red sin contador Inicio diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index a7a99e44d..951ab7d02 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -82,6 +82,7 @@ Pelit Sovellukset Sovelluksia ei löytynyt… + Tämä sivu tai resurssi ei ole saatavilla huollon vuoksi. Hae sovellusta Takaisin Tyhjennä haku diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index bc5f01263..7788bea76 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -87,9 +87,19 @@ Téléchargements Mises à jour Les mises à jour d\'application ne seront pas installées automatiquement + Aucune connexion Connexion impossible ! Merci de vérifier votre connexion internet puis réessayer Accueil Aucune application trouvée… + Cette page ou ressource est indisponible en raison d\'une maintenance. + Apps temporairement indisponibles + Open Source temporairement indisponible + Web Apps temporairement indisponibles + Nous ne pouvons pas joindre ce catalogue pour l\'instant. D\'autres sources d\'Apps peuvent encore fonctionner. + Aucun résultat dans Apps + Aucun résultat dans Open Source + Aucun résultat dans Web Apps + D\'autres sources d\'Apps peuvent fournir des résultats, veuillez vérifier les autres onglets/vos paramètres. Connexion avec un compte Google Choisissez comment vous connecter Se connecter avec Google uniquement dans App Lounge diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index 5e6902d1f..94e38ad7d 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -28,6 +28,7 @@ Til baka Hreinsa leit Engin forrit fundust… + Þessi síða eða auðlind er ekki tiltæk vegna viðhalds. Forrit Leikir Táknmynd flokks diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index d1e0c320d..f6e1f738c 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -32,6 +32,15 @@ Indietro Cancella ricerca Non ho trovato App… + Questa pagina o risorsa non è disponibile per manutenzione. + Apps temporaneamente non disponibili + Open Source temporaneamente non disponibile + Web Apps temporaneamente non disponibili + Non riusciamo a raggiungere questo catalogo al momento. Altre sorgenti di Apps potrebbero funzionare. + Nessun risultato in Apps + Nessun risultato in Open Source + Nessun risultato in Web Apps + Altre sorgenti di Apps potrebbero fornire risultati, controlla le altre schede/le impostazioni. App Giochi Icona Categorie @@ -99,6 +108,7 @@ Gli aggiornamenti App non verranno installati automaticamente Attesa connessione WiFi Le App a pagamento non sono ancora supportate da App Lounge. Un pò di pazienza e lo saranno. + Nessuna connessione Non riesco a connettermi! Verifica la connessione internet e ritenta Mostra una notifica quando sono disponibili aggiornamenti App Installa diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index deee7ecfd..e8529b6c6 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -9,6 +9,7 @@ 戻る 検索をクリア アプリが見つかりませんでした… + このページまたはリソースはメンテナンスのため利用できません。 アプリケーション ゲーム カテゴリーのアイコン diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 235591a0f..eddb63f21 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -68,6 +68,7 @@ Applikasjonen ble ikke funnet. Der er ikke nok tilgjengelig lagringsplass for å laste ned denne applikasjonen! Ukjent feil! + Denne siden eller ressursen er utilgjengelig på grunn av vedlikehold. Denne applikasjonen vil bli tilgjengelig senere! Applikasjoner som koster penger kan ikke installeres i anonym modus. Logg inn på din Google-konto for å installere betalte applikasjoner. Pakkenavn: %1$s diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 813255c9c..9d9682545 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -58,6 +58,7 @@ Je applicatie is niet gevonden. Er is niet genoeg geheugen beschikbaar om deze applicatie te downloaden! Onbekende fout! + Deze pagina of bron is niet beschikbaar vanwege onderhoud. Deze app zal binnenkort beschikbaar zijn! Betalende apps worden nog niet ondersteund in de App Lounge. Dit gaat binnenkort mogelijk zijn. Hebt u alstublieft nog een beetje geduld. Betaalde apps kunnen niet geïnstalleerd worden in anonieme modus. Om betalende apps te installeren, gelieve in te loggen op je Google account. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index b5a9b9372..a795394ae 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -10,6 +10,7 @@ Voltar Limpar pesquisa Nenhum aplicativo encontrado… + Esta página ou recurso está indisponível devido a manutenção. Aplicativos Jogos Ícone de Categorias diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index c1f51152d..2bf5019c5 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -53,6 +53,7 @@ Игры Приложения Приложения не найдены… + Эта страница или ресурс недоступны из-за технического обслуживания. Поиск приложения Назад Очистить поиск diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 60432be8b..ca2b0afb4 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -36,6 +36,7 @@ Hry Aplikácie Nenašli sa žiadne aplikácie… + Táto stránka alebo zdroj sú nedostupné z dôvodu údržby. Vyhľadajte aplikáciu Späť Vymazať vyhľadávanie diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index a85f26693..c2c7d8c69 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -24,6 +24,7 @@ Tillbaka Rensa sökning Inga appar hittades … + Denna sida eller resurs är inte tillgänglig på grund av underhåll. Appar Spel Öppen källkod diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 2baf2b1b8..6a16d769a 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -67,6 +67,7 @@ Ücretli uygulamalar henüz App Lounge\'da desteklenmiyor. Sadece biraz daha sabır, yakında bizimle olacaklar. Bu uygulama daha sonra kullanıma sunulacak! Bilinmeyen Hata! + Bu sayfa veya kaynak bakım nedeniyle kullanılamıyor. Bu uygulamayı indirmek için yeterli alan yok! Uygulamanız bulunamadı. Birşeyler ters gitti! diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 278190640..3191ab84d 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -53,6 +53,7 @@ Застосунки Ігри Нічого не знайдено… + Ця сторінка або ресурс недоступні через технічне обслуговування. Шукати застосунки Назад Очистити пошук diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 69a761f4f..14df3606f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -35,7 +35,15 @@ OPEN SOURCE WEB APPS No apps found… - Error in search + This page or resource is unavailable due to maintenance. + Apps temporarily unavailable + Open Source temporarily unavailable + Web Apps temporarily unavailable + We can’t reach this catalog right now. Other app sources may still work. + No results in Apps + No results in Open Source + No results in Web Apps + Other app sources may be able to provide results, please check the other tabs/your settings. Applications -- GitLab From c8683303e52e9e5556351e3580106ac9d8d82775 Mon Sep 17 00:00:00 2001 From: Nishith Khanna Date: Tue, 24 Feb 2026 19:55:27 +0530 Subject: [PATCH 02/22] fix lint after removing unused stirng --- app/src/main/res/values-de/strings.xml | 1 - app/src/main/res/values-es/strings.xml | 1 - app/src/main/res/values-fi/strings.xml | 1 - app/src/main/res/values-fr/strings.xml | 1 - app/src/main/res/values-is/strings.xml | 1 - app/src/main/res/values-it/strings.xml | 1 - app/src/main/res/values-ja/strings.xml | 1 - app/src/main/res/values-nb-rNO/strings.xml | 1 - app/src/main/res/values-nl/strings.xml | 1 - app/src/main/res/values-pt-rBR/strings.xml | 1 - app/src/main/res/values-ru/strings.xml | 1 - app/src/main/res/values-sk/strings.xml | 1 - app/src/main/res/values-sv/strings.xml | 1 - app/src/main/res/values-tr/strings.xml | 1 - app/src/main/res/values-uk/strings.xml | 1 - app/src/main/res/values/strings.xml | 1 - 16 files changed, 16 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index b3853d9c1..673aa0907 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -21,7 +21,6 @@ Aktualisierungen Einstellungen Keine Apps gefunden … - Diese Seite oder Ressource ist wegen Wartungsarbeiten nicht verfügbar. Apps vorübergehend nicht verfügbar Open Source vorübergehend nicht verfügbar Web Apps vorübergehend nicht verfügbar diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 3c49d0ba6..5a23bb888 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -37,7 +37,6 @@ Atrás Borrar búsqueda No se encontraron aplicaciones… - Esta página o recurso no está disponible por mantenimiento. Apps temporalmente no disponibles Open Source temporalmente no disponible Web Apps temporalmente no disponibles diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index 951ab7d02..a7a99e44d 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -82,7 +82,6 @@ Pelit Sovellukset Sovelluksia ei löytynyt… - Tämä sivu tai resurssi ei ole saatavilla huollon vuoksi. Hae sovellusta Takaisin Tyhjennä haku diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 7788bea76..e5a7aea70 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -91,7 +91,6 @@ Connexion impossible ! Merci de vérifier votre connexion internet puis réessayer Accueil Aucune application trouvée… - Cette page ou ressource est indisponible en raison d\'une maintenance. Apps temporairement indisponibles Open Source temporairement indisponible Web Apps temporairement indisponibles diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index 94e38ad7d..5e6902d1f 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -28,7 +28,6 @@ Til baka Hreinsa leit Engin forrit fundust… - Þessi síða eða auðlind er ekki tiltæk vegna viðhalds. Forrit Leikir Táknmynd flokks diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index f6e1f738c..a081d6958 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -32,7 +32,6 @@ Indietro Cancella ricerca Non ho trovato App… - Questa pagina o risorsa non è disponibile per manutenzione. Apps temporaneamente non disponibili Open Source temporaneamente non disponibile Web Apps temporaneamente non disponibili diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index e8529b6c6..deee7ecfd 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -9,7 +9,6 @@ 戻る 検索をクリア アプリが見つかりませんでした… - このページまたはリソースはメンテナンスのため利用できません。 アプリケーション ゲーム カテゴリーのアイコン diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index eddb63f21..235591a0f 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -68,7 +68,6 @@ Applikasjonen ble ikke funnet. Der er ikke nok tilgjengelig lagringsplass for å laste ned denne applikasjonen! Ukjent feil! - Denne siden eller ressursen er utilgjengelig på grunn av vedlikehold. Denne applikasjonen vil bli tilgjengelig senere! Applikasjoner som koster penger kan ikke installeres i anonym modus. Logg inn på din Google-konto for å installere betalte applikasjoner. Pakkenavn: %1$s diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 9d9682545..813255c9c 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -58,7 +58,6 @@ Je applicatie is niet gevonden. Er is niet genoeg geheugen beschikbaar om deze applicatie te downloaden! Onbekende fout! - Deze pagina of bron is niet beschikbaar vanwege onderhoud. Deze app zal binnenkort beschikbaar zijn! Betalende apps worden nog niet ondersteund in de App Lounge. Dit gaat binnenkort mogelijk zijn. Hebt u alstublieft nog een beetje geduld. Betaalde apps kunnen niet geïnstalleerd worden in anonieme modus. Om betalende apps te installeren, gelieve in te loggen op je Google account. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index a795394ae..b5a9b9372 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -10,7 +10,6 @@ Voltar Limpar pesquisa Nenhum aplicativo encontrado… - Esta página ou recurso está indisponível devido a manutenção. Aplicativos Jogos Ícone de Categorias diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 2bf5019c5..c1f51152d 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -53,7 +53,6 @@ Игры Приложения Приложения не найдены… - Эта страница или ресурс недоступны из-за технического обслуживания. Поиск приложения Назад Очистить поиск diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index ca2b0afb4..60432be8b 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -36,7 +36,6 @@ Hry Aplikácie Nenašli sa žiadne aplikácie… - Táto stránka alebo zdroj sú nedostupné z dôvodu údržby. Vyhľadajte aplikáciu Späť Vymazať vyhľadávanie diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index c2c7d8c69..a85f26693 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -24,7 +24,6 @@ Tillbaka Rensa sökning Inga appar hittades … - Denna sida eller resurs är inte tillgänglig på grund av underhåll. Appar Spel Öppen källkod diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 6a16d769a..2baf2b1b8 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -67,7 +67,6 @@ Ücretli uygulamalar henüz App Lounge\'da desteklenmiyor. Sadece biraz daha sabır, yakında bizimle olacaklar. Bu uygulama daha sonra kullanıma sunulacak! Bilinmeyen Hata! - Bu sayfa veya kaynak bakım nedeniyle kullanılamıyor. Bu uygulamayı indirmek için yeterli alan yok! Uygulamanız bulunamadı. Birşeyler ters gitti! diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 3191ab84d..278190640 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -53,7 +53,6 @@ Застосунки Ігри Нічого не знайдено… - Ця сторінка або ресурс недоступні через технічне обслуговування. Шукати застосунки Назад Очистити пошук diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 14df3606f..89e63a3d4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -35,7 +35,6 @@ OPEN SOURCE WEB APPS No apps found… - This page or resource is unavailable due to maintenance. Apps temporarily unavailable Open Source temporarily unavailable Web Apps temporarily unavailable -- GitLab From c5891e403885185f46e5fd84bf9024de8bb8d430 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Tue, 24 Feb 2026 13:50:52 +0600 Subject: [PATCH 03/22] refactor: update no connection UI --- .../main/res/drawable/ic_no_connection.xml | 10 +++++ app/src/main/res/layout/activity_main.xml | 44 ++++++++++++++----- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values-es/strings.xml | 2 +- app/src/main/res/values-fi/strings.xml | 2 +- app/src/main/res/values-fr/strings.xml | 2 +- app/src/main/res/values-is/strings.xml | 2 +- app/src/main/res/values-it/strings.xml | 2 +- app/src/main/res/values-ja/strings.xml | 2 +- app/src/main/res/values-nb-rNO/strings.xml | 2 +- app/src/main/res/values-nl/strings.xml | 2 +- app/src/main/res/values-pt-rBR/strings.xml | 2 +- app/src/main/res/values-ru/strings.xml | 2 +- app/src/main/res/values-sk/strings.xml | 2 +- app/src/main/res/values-sv/strings.xml | 2 +- app/src/main/res/values-tr/strings.xml | 2 +- app/src/main/res/values-uk/strings.xml | 2 +- app/src/main/res/values/strings.xml | 9 ++-- 18 files changed, 63 insertions(+), 30 deletions(-) create mode 100644 app/src/main/res/drawable/ic_no_connection.xml diff --git a/app/src/main/res/drawable/ic_no_connection.xml b/app/src/main/res/drawable/ic_no_connection.xml new file mode 100644 index 000000000..3ff04f04a --- /dev/null +++ b/app/src/main/res/drawable/ic_no_connection.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 5d8706c33..82c1b4703 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -23,24 +23,46 @@ android:layout_height="match_parent" tools:context=".ui.MainActivity"> - + tools:visibility="visible"> + + + + + + + + App-Aktualisierungen werden nicht automatisch installiert Auf ein unlimitiertes Netzwerk warten Keine Verbindung - Keine Verbindung möglich. Bitte überprüfe die Internetverbindung und versuche es erneut + Bitte überprüfe deine Internetverbindung und versuche es erneut. Start App-Suche Zurück diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 5a23bb888..c1bdd8417 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -105,7 +105,7 @@ Actualizaciones Las actualizaciones no se instalarán automáticamente Sin conexión - ¡No se pudo conectar! Chequea tu conexión a internet e inténtalo de nuevo + Por favor, comprueba tu conexión a internet e inténtalo de nuevo. Esperando una red sin contador Inicio Aplicaciones diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index a7a99e44d..c33493739 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -93,7 +93,7 @@ VAHVISTA Kun klikkaat vahvista, pääset sovelluksen Google Play -sivulle ja voit suorittaa oston loppuun selaimellasi. Klikkaa vahvista ostaaksesi %1$s hintaan %2$s. Osta %1$s - Yhteyden muodostaminen ei onnistu! Tarkista internetyhteytesi ja yritä uudelleen + Tarkista internetyhteytesi ja yritä uudelleen. Odotetaan mittaamatonta verkkoa Sovelluspäivityksiä ei asenneta automaattisesti Sovelluspäivitykset asennetaan automaattisesti diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index e5a7aea70..a1520b666 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -88,7 +88,7 @@ Mises à jour Les mises à jour d\'application ne seront pas installées automatiquement Aucune connexion - Connexion impossible ! Merci de vérifier votre connexion internet puis réessayer + Veuillez vérifier votre connexion Internet et réessayer. Accueil Aucune application trouvée… Apps temporairement indisponibles diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index 5e6902d1f..2ad5a76f4 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -123,7 +123,7 @@ Öll forrit eru af nýjustu útgáfu Vinsæl PWA-vefforrit Vinsælir PWA-leikir - Næ ekki að tengjast! Athugaðu internettenginguna þína og prófaðu svo aftur + Athugaðu internettenginguna þína og reyndu aftur. Féll á tímamörkum við að sækja forrit! Einhver vandamál í netkerfinu koma í veg fyrir að hægt sé að sækja öll forrit. \n diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index a081d6958..4197e28ea 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -108,7 +108,7 @@ Attesa connessione WiFi Le App a pagamento non sono ancora supportate da App Lounge. Un pò di pazienza e lo saranno. Nessuna connessione - Non riesco a connettermi! Verifica la connessione internet e ritenta + Controlla la tua connessione internet e riprova. Mostra una notifica quando sono disponibili aggiornamenti App Installa Annulla diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index deee7ecfd..f5f0ed433 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -124,7 +124,7 @@ %sの追加のファイル PWAの人気アプリ PWAの人気ゲーム - 接続できません!インターネットの接続を確認して、再度試してください + インターネット接続を確認して、もう一度お試しください。 %1$sのアップデートが%2$sに完了しました。 アプリのアップデートは自動的にインストールされます アプリのアップデートは自動的にインストールされません diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 235591a0f..feea4829e 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -44,7 +44,7 @@ \n \nÅpne instillinger for å kun se etter åpen kildekode-applikasjoner eller PWAer. Tidsavbrudd ved henting av applikasjoner! - Kan ikke koble til! Kontroller internettilgangen og prøv igjen + Kontroller internettilkoblingen din og prøv igjen. Oppdatering av %1$s applikasjoner ble fullført %2$s. Venter på ubegrenset nettverk Applikasjonsoppdateringer vil ikke bli installert automatisk diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 813255c9c..ae1a93a4d 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -33,7 +33,7 @@ Fout tijdens het laden van apps. Meer info Instellingen openen - Kan niet verbinden! Kijk alstublieft je internet verbinding na en probeer opnieuw + Controleer je internetverbinding en probeer het opnieuw. Update van %1$s apps voltooid op %2$s. Wachten op niet-gemeten netwerk App updates zullen niet automatisch geïnstalleerd worden diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index b5a9b9372..210f22403 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -118,7 +118,7 @@ Seu aplicativo será baixado automaticamente nesse dispositivo Você é muito jovem para poder instalar %1$s. Por favor, verifique com seus pais se sua faixa etária está correta ou desative o controle dos pais para poder instalá-lo. - Não é possível conectar! Verifique sua conexão com a Internet e tente novamente + Verifique sua conexão com a internet e tente novamente. Atualização de %1$s aplicativos concluída em %2$s. CONFIRMAR Semanal diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index c1f51152d..aeb36c182 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -100,7 +100,7 @@ \n \nОткройте настройки, чтобы искать только Open Source приложения или PWA. Тайм-аут загрузки приложений! - Не удается подключиться! Пожалуйста, проверьте подключение к Интернету и повторите попытку + Проверьте подключение к интернету и попробуйте снова. Обновление приложений %1$s завершено на %2$s. В ожидании безлимитной сети Обновления приложений не будут устанавливаться автоматически diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 60432be8b..7c05a5754 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -152,7 +152,7 @@ Takéto aplikácie sa budú aktualizovať z kategórií bežných a open source Aktualizácie aplikácií sa nebudú inštalovať automaticky Čaká sa na nemeranú sieť Aktualizácia %1$s aplikácií bola dokončená %2$s. - Nedá sa pripojiť! Skontrolujte internetové pripojenie a skúste to znova + Skontrolujte internetové pripojenie a skúste to znova. Vypršal časový limit pri načítavaní aplikácií! Niektorý sieťový problém bráni načítaniu všetkých aplikácií. diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index a85f26693..b48426901 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -117,7 +117,7 @@ Appuppdateringar kommer installera automatiskt Appuppdateringar kommer inte att installeras automatiskt Mer info - Kan inte ansluta! Kontrollera din internetanslutning och försök igen + Kontrollera din internetanslutning och försök igen. Öppna inställningar Det anonyma kontot du använder är inte tillgängligt. Uppdatera sessionen för att få ett annat. UPPADATERA SESSIONEN diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 2baf2b1b8..c7e2fe98d 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -134,7 +134,7 @@ %1$s yükleyebilmek için çok küçüksünüz. Lütfen yaş grubunuzun doğru olup olmadığını ebeveyninizle kontrol edin veya yükleyebilmek için ebeveyn kontrolünü devre dışı bırakın. Bu uygulama uygunsuz içerik içerebilir. Ücretli uygulamalar anonim modda yüklenemez. Ücretli uygulamaları yüklemek için lütfen Google hesabınıza giriş yapın. - Bağlantı kurulamıyor! Lütfen internet bağlantınızı kontrol edin ve tekrar deneyin + Lütfen internet bağlantınızı kontrol edin ve tekrar deneyin. Uygulamaları getirirken zaman aşımı! Bazı ağ sorunları tüm uygulamaların getirilmesini engelliyor. Ayarları Aç diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 278190640..1799676f5 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -145,7 +145,7 @@ \n \nВідкрийте налаштування, щоб перевірити опції \"Тільки застосунки з відкритим кодом\" та \"Тільки прогресивні вебзастосунки\". Час запиту на отримання застосунків вичерпано! - Неможливо приєднатись до мережі! Будь ласка, перевірте налаштування Вашої мережі та спробуйте знову + Перевірте підключення до інтернету та спробуйте ще раз. Оновлення застосунків %1$s було завершено %2$s. Це оновлення не може бути застосоване, тому що не співпадають сигнатури версії %1$s та версії, що встановлена на Вашому телефоні. Щоб виправити це, Ви можете видалити %1$s, а потім знову встановити з Магазину.

Примітка: Це повідомлення не показуватиметься знову.
Щотижня diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 89e63a3d4..5cf37d4f4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -31,9 +31,9 @@ Search for an app Back Clear search - APPS - OPEN SOURCE - WEB APPS + APPS + OPEN SOURCE + WEB APPS No apps found… Apps temporarily unavailable Open Source temporarily unavailable @@ -195,7 +195,8 @@ updateUnmeteredOnly updateAppsFromOtherStores - Can\'t connect! Please check your internet connection and try again + No connection + Please check your internet connection and try again. Timeout fetching applications! Some network issue is preventing fetching all applications. -- GitLab From de7d229def8ae700a973d5cd1a3cd79a6d4b6719 Mon Sep 17 00:00:00 2001 From: Nishith Khanna Date: Tue, 24 Feb 2026 19:31:50 +0530 Subject: [PATCH 04/22] fix no connection icon by removing alpha from vector --- app/src/main/res/drawable/ic_no_connection.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/res/drawable/ic_no_connection.xml b/app/src/main/res/drawable/ic_no_connection.xml index 3ff04f04a..bfe20d095 100644 --- a/app/src/main/res/drawable/ic_no_connection.xml +++ b/app/src/main/res/drawable/ic_no_connection.xml @@ -5,6 +5,5 @@ android:viewportHeight="48"> + android:fillColor="#000000" /> -- GitLab From b3e64b5051d9ee0ccf320877854087c12da1ecae Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Thu, 5 Feb 2026 12:24:46 +0600 Subject: [PATCH 05/22] refactor(ui): align search tabs color and text style --- .../e/apps/ui/compose/components/SearchTabs.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchTabs.kt b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchTabs.kt index a9d810c47..cef3cc0d6 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchTabs.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchTabs.kt @@ -45,13 +45,14 @@ fun SearchTabs( modifier: Modifier = Modifier, ) { SecondaryTabRow( - modifier = modifier, + modifier = modifier.padding(horizontal = 16.dp), selectedTabIndex = selectedIndex, indicator = { if (selectedIndex in tabs.indices) { SecondaryIndicator( modifier = Modifier.tabIndicatorOffset(selectedIndex), - color = MaterialTheme.colorScheme.primary, + height = 2.dp, + color = MaterialTheme.colorScheme.tertiary, ) } }, @@ -64,14 +65,14 @@ fun SearchTabs( Tab( selected = index == selectedIndex, onClick = { onTabSelect(tab, index) }, - selectedContentColor = MaterialTheme.colorScheme.primary, - unselectedContentColor = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.64f), + selectedContentColor = MaterialTheme.colorScheme.tertiary, + unselectedContentColor = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.60f), ) { Text( text = label, modifier = Modifier.padding(vertical = 12.dp), style = MaterialTheme.typography.labelLarge.copy( - fontWeight = FontWeight.SemiBold, + fontWeight = FontWeight.Medium, letterSpacing = 0.4.sp, ), ) -- GitLab From 152499b6b976ee4fa6707b4cfdf5dafe7efb0be3 Mon Sep 17 00:00:00 2001 From: Saalim Quadri Date: Mon, 9 Feb 2026 14:17:07 +0530 Subject: [PATCH 06/22] feat: Set correct colors in TopSeachBar Signed-off-by: Saalim Quadri --- .../e/apps/ui/compose/screens/SearchScreen.kt | 45 ++++++++++--------- .../e/apps/ui/compose/screens/SearchTopBar.kt | 25 ++++++----- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchScreen.kt b/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchScreen.kt index 38cefd2b2..b2cb75ac2 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchScreen.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchScreen.kt @@ -22,6 +22,8 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -108,26 +110,29 @@ fun SearchScreen( Scaffold( modifier = modifier, topBar = { - SearchTopBar( - uiState = uiState, - expanded = isSearchExpanded, - showSuggestions = showSuggestions, - focusRequester = focusRequester, - focusManager = focusManager, - onQueryChange = onQueryChange, - onClearQuery = onClearQuery, - onSearchSubmit = onSubmitSearch, - onSuggestionSelect = onSuggestionSelect, - onExpandedChange = { expanded -> - isSearchExpanded = expanded - if (expanded) { - focusRequester.requestFocus() - } else { - focusManager.clearFocus() - } - }, - onBack = onBackClick, - ) + Column { + SearchTopBar( + uiState = uiState, + expanded = isSearchExpanded, + showSuggestions = showSuggestions, + focusRequester = focusRequester, + focusManager = focusManager, + onQueryChange = onQueryChange, + onClearQuery = onClearQuery, + onSearchSubmit = onSubmitSearch, + onSuggestionSelect = onSuggestionSelect, + onExpandedChange = { expanded -> + isSearchExpanded = expanded + if (expanded) { + focusRequester.requestFocus() + } else { + focusManager.clearFocus() + } + }, + onBack = onBackClick, + ) + HorizontalDivider(color = MaterialTheme.colorScheme.tertiary) + } }, ) { innerPadding -> Column( diff --git a/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchTopBar.kt b/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchTopBar.kt index 458de70f5..4f5285d47 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchTopBar.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchTopBar.kt @@ -21,12 +21,12 @@ package foundation.e.apps.ui.compose.screens import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Close -import androidx.compose.material.icons.filled.Search import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -35,7 +35,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SearchBar import androidx.compose.material3.SearchBarDefaults import androidx.compose.material3.Text -import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -45,6 +44,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusManager import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource @@ -75,9 +75,12 @@ fun SearchTopBar( modifier = modifier .fillMaxWidth() .testTag(SearchTopBarTestTags.SEARCH_BAR), + shape = RectangleShape, + shadowElevation = 0.dp, + tonalElevation = 0.dp, colors = SearchBarDefaults.colors( - containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp), - dividerColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f), + containerColor = MaterialTheme.colorScheme.surface, + dividerColor = MaterialTheme.colorScheme.tertiary, ), expanded = expanded, onExpandedChange = { isExpanded -> @@ -103,6 +106,11 @@ fun SearchTopBar( onExpandedChange = { isExpanded -> onExpandedChange(isExpanded) }, + colors = SearchBarDefaults.inputFieldColors( + unfocusedContainerColor = MaterialTheme.colorScheme.surface, + focusedContainerColor = MaterialTheme.colorScheme.surface, + cursorColor = MaterialTheme.colorScheme.tertiary, + ), placeholder = { Text(text = stringResource(id = R.string.search_hint)) }, leadingIcon = { IconButton( @@ -115,6 +123,7 @@ fun SearchTopBar( Icon( imageVector = Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(id = R.string.search_back_button), + modifier = Modifier.size(28.dp), ) } }, @@ -148,7 +157,7 @@ fun SearchTopBar( }, modifier = Modifier .fillMaxWidth() - .background(MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp)), + .background(MaterialTheme.colorScheme.surface), ) } } @@ -174,11 +183,7 @@ private fun SuggestionList( .testTag("${SearchTopBarTestTags.SUGGESTION_ITEM_PREFIX}$index"), headlineContent = { Text(text = suggestion) }, leadingContent = { - Icon( - imageVector = Icons.Filled.Search, - contentDescription = stringResource(id = R.string.menu_search), - tint = MaterialTheme.colorScheme.onSurfaceVariant, - ) + // No-op but we like the space :) }, ) } -- GitLab From 8a9ef39762d21a4ebdf5a8ddb359b8e77648d497 Mon Sep 17 00:00:00 2001 From: Saalim Quadri Date: Mon, 9 Feb 2026 14:35:14 +0530 Subject: [PATCH 07/22] feat: Show SearchResults in main content area Signed-off-by: Saalim Quadri --- .../ui/compose/screens/SearchTopBarTest.kt | 102 +-------------- .../compose/components/SearchInitialState.kt | 4 +- .../e/apps/ui/compose/screens/SearchScreen.kt | 117 +++++++++++------- .../e/apps/ui/compose/screens/SearchTopBar.kt | 93 ++------------ 4 files changed, 92 insertions(+), 224 deletions(-) diff --git a/app/src/androidTest/java/foundation/e/apps/ui/compose/screens/SearchTopBarTest.kt b/app/src/androidTest/java/foundation/e/apps/ui/compose/screens/SearchTopBarTest.kt index d6bc044b4..d1a35e2f2 100644 --- a/app/src/androidTest/java/foundation/e/apps/ui/compose/screens/SearchTopBarTest.kt +++ b/app/src/androidTest/java/foundation/e/apps/ui/compose/screens/SearchTopBarTest.kt @@ -42,6 +42,7 @@ import androidx.compose.ui.test.performTextInput import androidx.test.ext.junit.runners.AndroidJUnit4 import foundation.e.apps.R import foundation.e.apps.ui.search.v2.SearchUiState +import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Rule import org.junit.Test @@ -53,16 +54,13 @@ class SearchTopBarTest { val composeRule = createAndroidComposeRule() @Test - fun typingQuery_expandsSearchBar_andUpdatesQueryState() { + fun typingQuery_updatesQueryState() { val recorder = SearchTopBarRecorder() val hintText = composeRule.activity.getString(R.string.search_hint) composeRule.setContent { SearchTopBarTestContent( initialQuery = "", - suggestions = emptyList(), - initialExpanded = false, - showSuggestions = false, recorder = recorder, ) } @@ -78,21 +76,17 @@ class SearchTopBarTest { .performTextInput("camera") composeRule.runOnIdle { - assertTrue(recorder.expandedChanges.contains(true)) - assertTrue(recorder.queryChanges.contains("camera")) + assertEquals("camera", recorder.queryChanges.lastOrNull()) } } @Test - fun submitQuery_collapsesSearchBar_andClearsFocus() { + fun submitQuery_clearsFocus_andCallsSubmit() { val recorder = SearchTopBarRecorder() composeRule.setContent { SearchTopBarTestContent( initialQuery = "vpn", - suggestions = emptyList(), - initialExpanded = true, - showSuggestions = false, recorder = recorder, ) } @@ -103,7 +97,6 @@ class SearchTopBarTest { inputField.performImeAction() composeRule.runOnIdle { - assertTrue(recorder.expandedChanges.contains(false)) assertTrue(recorder.searchSubmissions.contains("vpn")) } @@ -112,15 +105,12 @@ class SearchTopBarTest { } @Test - fun clearButton_clearsQuery_keepsExpanded_andFocusesInput() { + fun clearButton_clearsQuery_andFocusesInput() { val recorder = SearchTopBarRecorder() composeRule.setContent { SearchTopBarTestContent( initialQuery = "maps", - suggestions = emptyList(), - initialExpanded = true, - showSuggestions = false, recorder = recorder, ) } @@ -134,7 +124,6 @@ class SearchTopBarTest { composeRule.runOnIdle { assertTrue(recorder.clearTapped) - assertTrue(recorder.expandedChanges.contains(true)) } composeRule.onNodeWithTag(SearchTopBarTestTags.INPUT_FIELD) @@ -148,9 +137,6 @@ class SearchTopBarTest { composeRule.setContent { SearchTopBarTestContent( initialQuery = "news", - suggestions = emptyList(), - initialExpanded = true, - showSuggestions = false, recorder = recorder, ) } @@ -169,75 +155,11 @@ class SearchTopBarTest { composeRule.onNodeWithTag(SearchTopBarTestTags.INPUT_FIELD) .assertIsNotFocused() } - - @Test - fun suggestions_callbackFires_whenSuggestionSelected() { - // Material3 SearchBar renders dropdown in a popup window inaccessible to standard - // Compose test APIs. This test verifies the callback logic is wired correctly - // by simulating a suggestion selection through the callback. - val recorder = SearchTopBarRecorder() - val suggestions = listOf("camera", "camera apps", "camera pro") - var simulateSuggestionClick: ((String) -> Unit)? = null - - composeRule.setContent { - var query by remember { mutableStateOf("cam") } - var expanded by remember { mutableStateOf(true) } - val focusRequester = remember { FocusRequester() } - val focusManager = LocalFocusManager.current - - // Capture the suggestion select callback for manual invocation - simulateSuggestionClick = { suggestion -> - expanded = false - focusManager.clearFocus() - recorder.suggestionSelections.add(suggestion) - recorder.expandedChanges.add(false) - } - - SearchTopBar( - uiState = SearchUiState( - query = query, - suggestions = suggestions, - ), - expanded = expanded, - showSuggestions = expanded, - focusRequester = focusRequester, - focusManager = focusManager, - onQueryChange = { query = it }, - onClearQuery = { query = "" }, - onSearchSubmit = {}, - onSuggestionSelect = { suggestion -> - expanded = false - focusManager.clearFocus() - recorder.suggestionSelections.add(suggestion) - recorder.expandedChanges.add(false) - }, - onExpandedChange = { expanded = it }, - onBack = {}, - modifier = Modifier.fillMaxSize(), - ) - } - - // Verify the SearchBar is displayed and expanded - composeRule.onNodeWithTag(SearchTopBarTestTags.SEARCH_BAR) - .assertIsDisplayed() - - // Simulate suggestion selection via callback - composeRule.runOnIdle { - simulateSuggestionClick?.invoke("camera apps") - } - - composeRule.runOnIdle { - assertTrue(recorder.expandedChanges.contains(false)) - assertTrue(recorder.suggestionSelections.contains("camera apps")) - } - } } private class SearchTopBarRecorder { val queryChanges = mutableListOf() val searchSubmissions = mutableListOf() - val suggestionSelections = mutableListOf() - val expandedChanges = mutableListOf() var clearTapped = false var backTapped = false } @@ -245,23 +167,16 @@ private class SearchTopBarRecorder { @Composable private fun SearchTopBarTestContent( initialQuery: String, - suggestions: List, - initialExpanded: Boolean, - showSuggestions: Boolean, recorder: SearchTopBarRecorder, ) { var query by remember { mutableStateOf(initialQuery) } - var expanded by remember { mutableStateOf(initialExpanded) } val focusRequester = remember { FocusRequester() } val focusManager = LocalFocusManager.current SearchTopBar( uiState = SearchUiState( query = query, - suggestions = suggestions, ), - expanded = expanded, - showSuggestions = showSuggestions && expanded, focusRequester = focusRequester, focusManager = focusManager, onQueryChange = { updatedQuery -> @@ -275,13 +190,6 @@ private fun SearchTopBarTestContent( onSearchSubmit = { submittedQuery -> recorder.searchSubmissions.add(submittedQuery) }, - onSuggestionSelect = { suggestion -> - recorder.suggestionSelections.add(suggestion) - }, - onExpandedChange = { isExpanded -> - expanded = isExpanded - recorder.expandedChanges.add(isExpanded) - }, onBack = { recorder.backTapped = true }, diff --git a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchInitialState.kt b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchInitialState.kt index be1e7a536..e01c1329d 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchInitialState.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchInitialState.kt @@ -51,7 +51,7 @@ fun SearchInitialState(modifier: Modifier = Modifier) { Icon( imageVector = Icons.Outlined.Search, contentDescription = null, - tint = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.45f), + tint = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f), modifier = Modifier .padding(bottom = 4.dp) .size(72.dp), @@ -59,7 +59,7 @@ fun SearchInitialState(modifier: Modifier = Modifier) { Text( text = stringResource(id = R.string.search_hint), style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.72f), + color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.72f), ) } } diff --git a/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchScreen.kt b/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchScreen.kt index b2cb75ac2..5b74ad295 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchScreen.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchScreen.kt @@ -18,13 +18,19 @@ package foundation.e.apps.ui.compose.screens +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.ListItem +import androidx.compose.material3.ListItemDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -80,9 +86,7 @@ fun SearchScreen( val lifecycleOwner = LocalLifecycleOwner.current val focusRequester = remember { FocusRequester() } val shouldAutoFocus = !uiState.hasSubmittedSearch - var isSearchExpanded by rememberSaveable { mutableStateOf(shouldAutoFocus) } var hasRequestedInitialFocus by rememberSaveable { mutableStateOf(false) } - val showSuggestions = isSearchExpanded && uiState.isSuggestionVisible LaunchedEffect(lifecycleOwner, shouldAutoFocus) { lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) { @@ -92,18 +96,13 @@ fun SearchScreen( focusRequester.requestFocus() keyboardController?.show() } - } else { - // Intentionally no-op; the initial focus request has already happened. } } } LaunchedEffect(uiState.hasSubmittedSearch) { if (uiState.hasSubmittedSearch) { - isSearchExpanded = false focusManager.clearFocus() - } else { - // Intentionally no-op; results are not active so focus remains unchanged. } } @@ -113,25 +112,17 @@ fun SearchScreen( Column { SearchTopBar( uiState = uiState, - expanded = isSearchExpanded, - showSuggestions = showSuggestions, focusRequester = focusRequester, focusManager = focusManager, onQueryChange = onQueryChange, onClearQuery = onClearQuery, onSearchSubmit = onSubmitSearch, - onSuggestionSelect = onSuggestionSelect, - onExpandedChange = { expanded -> - isSearchExpanded = expanded - if (expanded) { - focusRequester.requestFocus() - } else { - focusManager.clearFocus() - } - }, onBack = onBackClick, ) - HorizontalDivider(color = MaterialTheme.colorScheme.tertiary) + HorizontalDivider( + color = MaterialTheme.colorScheme.tertiary, + modifier = Modifier.padding(top = 8.dp), + ) } }, ) { innerPadding -> @@ -146,33 +137,71 @@ fun SearchScreen( val shouldShowResults = uiState.hasSubmittedSearch && uiState.selectedTab != null && uiState.availableTabs.isNotEmpty() + val shouldShowSuggestions = + !uiState.hasSubmittedSearch && uiState.isSuggestionVisible && uiState.suggestions.isNotEmpty() - if (shouldShowResults) { - SearchResultsContent( - tabs = uiState.availableTabs, - selectedTab = uiState.selectedTab!!, - fossItems = fossItems, - pwaItems = pwaItems, - playStoreItems = playStoreItems, - searchVersion = searchVersion, - getScrollPosition = getScrollPosition, - onScrollPositionChange = onScrollPositionChange, - onTabSelect = onTabSelect, - modifier = Modifier - .fillMaxWidth() - .padding(top = 8.dp), - onResultClick = onResultClick, - onPrimaryActionClick = onPrimaryAction, - onShowMoreClick = onShowMoreClick, - onPrivacyClick = onPrivacyClick, - installButtonStateProvider = installButtonStateProvider, - ) - } else { - SearchInitialState( - modifier = Modifier - .fillMaxWidth(), - ) + when { + shouldShowResults -> { + SearchResultsContent( + tabs = uiState.availableTabs, + selectedTab = uiState.selectedTab!!, + fossItems = fossItems, + pwaItems = pwaItems, + playStoreItems = playStoreItems, + searchVersion = searchVersion, + getScrollPosition = getScrollPosition, + onScrollPositionChange = onScrollPositionChange, + onTabSelect = onTabSelect, + modifier = Modifier + .fillMaxWidth() + .padding(top = 8.dp), + onResultClick = onResultClick, + onPrimaryActionClick = onPrimaryAction, + onShowMoreClick = onShowMoreClick, + onPrivacyClick = onPrivacyClick, + installButtonStateProvider = installButtonStateProvider, + ) + } + shouldShowSuggestions -> { + SuggestionList( + suggestions = uiState.suggestions, + onSuggestionSelect = { suggestion -> + focusManager.clearFocus() + onSuggestionSelect(suggestion) + }, + modifier = Modifier.fillMaxWidth(), + ) + } + else -> { + SearchInitialState( + modifier = Modifier.fillMaxSize(), + ) + } } } } } + +@Composable +private fun SuggestionList( + suggestions: List, + onSuggestionSelect: (String) -> Unit, + modifier: Modifier = Modifier, +) { + LazyColumn(modifier = modifier) { + itemsIndexed( + items = suggestions, + key = { _, suggestion -> suggestion }, + ) { _, suggestion -> + ListItem( + modifier = Modifier + .fillMaxWidth() + .clickable { onSuggestionSelect(suggestion) }, + colors = ListItemDefaults.colors( + containerColor = MaterialTheme.colorScheme.background, + ), + headlineContent = { Text(text = suggestion) }, + ) + } + } +} diff --git a/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchTopBar.kt b/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchTopBar.kt index 4f5285d47..4b9baea6b 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchTopBar.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchTopBar.kt @@ -18,28 +18,20 @@ package foundation.e.apps.ui.compose.screens -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Close import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.ListItem import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SearchBar import androidx.compose.material3.SearchBarDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusManager import androidx.compose.ui.focus.FocusRequester @@ -59,15 +51,11 @@ import foundation.e.apps.ui.search.v2.SearchUiState @Composable fun SearchTopBar( uiState: SearchUiState, - expanded: Boolean, - showSuggestions: Boolean, focusRequester: FocusRequester, focusManager: FocusManager, onQueryChange: (String) -> Unit, onClearQuery: () -> Unit, onSearchSubmit: (String) -> Unit, - onSuggestionSelect: (String) -> Unit, - onExpandedChange: (Boolean) -> Unit, onBack: () -> Unit, modifier: Modifier = Modifier, ) { @@ -79,13 +67,11 @@ fun SearchTopBar( shadowElevation = 0.dp, tonalElevation = 0.dp, colors = SearchBarDefaults.colors( - containerColor = MaterialTheme.colorScheme.surface, + containerColor = MaterialTheme.colorScheme.background, dividerColor = MaterialTheme.colorScheme.tertiary, ), - expanded = expanded, - onExpandedChange = { isExpanded -> - onExpandedChange(isExpanded) - }, + expanded = false, + onExpandedChange = {}, inputField = { SearchBarDefaults.InputField( modifier = Modifier @@ -93,22 +79,16 @@ fun SearchTopBar( .focusRequester(focusRequester) .testTag(SearchTopBarTestTags.INPUT_FIELD), query = uiState.query, - onQueryChange = { query -> - onExpandedChange(true) - onQueryChange(query) - }, + onQueryChange = onQueryChange, onSearch = { query -> - onExpandedChange(false) focusManager.clearFocus() onSearchSubmit(query) }, - expanded = expanded, - onExpandedChange = { isExpanded -> - onExpandedChange(isExpanded) - }, + expanded = false, + onExpandedChange = {}, colors = SearchBarDefaults.inputFieldColors( - unfocusedContainerColor = MaterialTheme.colorScheme.surface, - focusedContainerColor = MaterialTheme.colorScheme.surface, + unfocusedContainerColor = MaterialTheme.colorScheme.background, + focusedContainerColor = MaterialTheme.colorScheme.background, cursorColor = MaterialTheme.colorScheme.tertiary, ), placeholder = { Text(text = stringResource(id = R.string.search_hint)) }, @@ -133,7 +113,6 @@ fun SearchTopBar( modifier = Modifier.testTag(SearchTopBarTestTags.CLEAR_BUTTON), onClick = { onClearQuery() - onExpandedChange(true) focusRequester.requestFocus() }, ) { @@ -146,48 +125,7 @@ fun SearchTopBar( }, ) }, - ) { - if (showSuggestions) { - SuggestionList( - suggestions = uiState.suggestions, - onSuggestionSelect = { suggestion -> - onExpandedChange(false) - focusManager.clearFocus() - onSuggestionSelect(suggestion) - }, - modifier = Modifier - .fillMaxWidth() - .background(MaterialTheme.colorScheme.surface), - ) - } - } -} - -@Composable -private fun SuggestionList( - suggestions: List, - onSuggestionSelect: (String) -> Unit, - modifier: Modifier = Modifier, -) { - LazyColumn( - modifier = modifier.testTag(SearchTopBarTestTags.SUGGESTIONS_LIST), - ) { - itemsIndexed( - items = suggestions, - key = { _, suggestion -> suggestion }, - ) { index, suggestion -> - ListItem( - modifier = Modifier - .fillMaxWidth() - .clickable { onSuggestionSelect(suggestion) } - .testTag("${SearchTopBarTestTags.SUGGESTION_ITEM_PREFIX}$index"), - headlineContent = { Text(text = suggestion) }, - leadingContent = { - // No-op but we like the space :) - }, - ) - } - } + ) {} } internal object SearchTopBarTestTags { @@ -195,8 +133,6 @@ internal object SearchTopBarTestTags { const val INPUT_FIELD = "search_top_bar_input_field" const val BACK_BUTTON = "search_top_bar_back_button" const val CLEAR_BUTTON = "search_top_bar_clear_button" - const val SUGGESTIONS_LIST = "search_top_bar_suggestions_list" - const val SUGGESTION_ITEM_PREFIX = "search_top_bar_suggestion_" } @Preview(showBackground = true) @@ -205,7 +141,6 @@ private fun SearchTopBarPreview() { AppTheme(darkTheme = true) { val focusRequester = remember { FocusRequester() } val focusManager = LocalFocusManager.current - var expanded by remember { mutableStateOf(true) } val sampleState = SearchUiState( query = "browser", suggestions = listOf( @@ -226,15 +161,11 @@ private fun SearchTopBarPreview() { SearchTopBar( uiState = sampleState, - expanded = expanded, - showSuggestions = expanded && sampleState.suggestions.isNotEmpty(), focusRequester = focusRequester, focusManager = focusManager, - onQueryChange = { expanded = true }, - onClearQuery = { expanded = true }, - onSearchSubmit = { expanded = false }, - onSuggestionSelect = { expanded = false }, - onExpandedChange = { expanded = it }, + onQueryChange = {}, + onClearQuery = {}, + onSearchSubmit = {}, onBack = {}, ) } -- GitLab From bceff7f2709370b1f312cb9cc0fbc962f7eeb599 Mon Sep 17 00:00:00 2001 From: Saalim Quadri Date: Mon, 9 Feb 2026 15:13:19 +0530 Subject: [PATCH 08/22] feat: Properly handle button pending/install states - Squash of following commits: https://gitlab.e.foundation/e/os/apps/-/commit/012e2fb5a193d2d5c6b3a21a0c5876e1e94c9c5d, https://gitlab.e.foundation/e/os/apps/-/commit/f545d61be06c07ead8d2036e11a4545a22baf7c7, https://gitlab.e.foundation/e/os/apps/-/commit/d4f98835c0d5216a3b8fd3e766a2e7cedff41c11, https://gitlab.e.foundation/e/os/apps/-/commit/5784a2ecba3fcb4fc6ee3b17c4ecdc882fa42a84 Signed-off-by: Saalim Quadri --- .../components/SearchResultListItem.kt | 57 +++++++------- .../components/SearchResultsContent.kt | 1 + .../ui/compose/state/InstallButtonState.kt | 1 + .../compose/state/InstallButtonStateMapper.kt | 29 +++++-- .../e/apps/ui/search/v2/SearchFragmentV2.kt | 78 +++++++++++++------ .../e/apps/ui/search/v2/SearchViewModelV2.kt | 18 ++++- .../state/InstallButtonStateMapperTest.kt | 5 +- 7 files changed, 128 insertions(+), 61 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt index c764aadcf..f32d37fba 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt @@ -33,6 +33,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults @@ -239,6 +240,7 @@ private fun PrivacyBadge( .size(16.dp) .testTag(SearchResultListItemTestTags.PRIVACY_PROGRESS), strokeWidth = 2.dp, + color = MaterialTheme.colorScheme.tertiary, ) } else { Text( @@ -270,38 +272,35 @@ private fun PrimaryActionArea( .clickable(onClick = onShowMoreClick), ) return - } else { - // render the primary action button } - val accentColor = MaterialTheme.colorScheme.tertiary - - val labelTextColor = when { - uiState.isFilledStyle -> MaterialTheme.colorScheme.onPrimary - else -> accentColor - } + Column(horizontalAlignment = Alignment.End) { + val accentColor = MaterialTheme.colorScheme.tertiary + val labelTextColor = when { + uiState.isFilledStyle -> Color.White + else -> accentColor + } - val buttonContent: @Composable () -> Unit = { - val showSpinner = uiState.isInProgress && uiState.label.isBlank() - if (showSpinner) { - CircularProgressIndicator( - modifier = Modifier - .size(16.dp) - .testTag(SearchResultListItemTestTags.PRIMARY_PROGRESS), - strokeWidth = 2.dp, - color = labelTextColor, - ) - } else { - Text( - text = uiState.label, - maxLines = 1, - overflow = TextOverflow.Clip, - color = labelTextColor, - ) + val buttonContent: @Composable () -> Unit = { + val showSpinner = uiState.isInProgress && uiState.label.isBlank() + if (showSpinner) { + CircularProgressIndicator( + modifier = Modifier + .size(16.dp) + .testTag(SearchResultListItemTestTags.PRIMARY_PROGRESS), + strokeWidth = 2.dp, + color = labelTextColor, + ) + } else { + Text( + text = uiState.label, + maxLines = 1, + overflow = TextOverflow.Clip, + color = labelTextColor, + ) + } } - } - Column(horizontalAlignment = Alignment.End) { val borderColor = when { uiState.isFilledStyle -> Color.Transparent uiState.enabled -> accentColor @@ -311,6 +310,7 @@ private fun PrimaryActionArea( onClick = onPrimaryClick, enabled = uiState.enabled, modifier = Modifier + .widthIn(min = 88.dp) .height(40.dp) .testTag(SearchResultListItemTestTags.PRIMARY_BUTTON), shape = RoundedCornerShape(4.dp), @@ -353,7 +353,7 @@ private fun PlaceholderRow(modifier: Modifier = Modifier) { .testTag(SearchResultListItemTestTags.PLACEHOLDER), contentAlignment = Alignment.Center, ) { - CircularProgressIndicator() + CircularProgressIndicator(color = MaterialTheme.colorScheme.tertiary) } } @@ -379,6 +379,7 @@ data class PrimaryActionUiState( val isFilledStyle: Boolean, val showMore: Boolean = false, val actionIntent: InstallButtonAction = InstallButtonAction.NoOp, + val progressFraction: Float = 0f, ) internal object SearchResultListItemTestTags { diff --git a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt index dee254cce..7cb9b0178 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt @@ -595,6 +595,7 @@ private fun Application.toSearchResultUiState(buttonState: InstallButtonState): isFilledStyle = buttonState.style == InstallButtonStyle.AccentFill, showMore = false, actionIntent = buttonState.actionIntent, + progressFraction = buttonState.progressFraction, ), iconUrl = iconUrl, placeholderResId = null, diff --git a/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonState.kt b/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonState.kt index 5aa16d20b..6a9b07e3d 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonState.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonState.kt @@ -31,6 +31,7 @@ data class InstallButtonState( val style: InstallButtonStyle = InstallButtonStyle.AccentOutline, val showProgressBar: Boolean = false, val progressPercentText: String? = null, + val progressFraction: Float = 0f, val actionIntent: InstallButtonAction = InstallButtonAction.NoOp, @StringRes val snackbarMessageId: Int? = null, val dialogType: InstallDialogType? = null, diff --git a/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt b/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt index b24d7f013..5df5c1117 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt @@ -32,7 +32,8 @@ fun mapAppToInstallState(input: InstallButtonStateInput): InstallButtonState { Status.INSTALLED -> mapInstalled() Status.UPDATABLE -> mapUpdatable(input) Status.UNAVAILABLE -> mapUnavailable(input) - Status.QUEUED, Status.AWAITING, Status.DOWNLOADING, Status.DOWNLOADED -> mapDownloading(input, status) + Status.QUEUED, Status.AWAITING -> mapQueued(status) + Status.DOWNLOADING, Status.DOWNLOADED -> mapDownloading(input, status) Status.INSTALLING -> mapInstalling(status) Status.BLOCKED -> mapBlocked(input) Status.INSTALLATION_ISSUE -> mapInstallationIssue(input) @@ -136,13 +137,27 @@ private fun mapUnavailablePaid(input: InstallButtonStateInput): InstallButtonSta } } +private fun mapQueued(status: Status): InstallButtonState { + return InstallButtonState( + label = ButtonLabel(resId = R.string.cancel), + progressPercentText = null, + enabled = true, + style = buildStyleFor(status, enabled = true), + actionIntent = InstallButtonAction.CancelDownload, + statusTag = StatusTag.Downloading, + rawStatus = status, + ) +} + private fun mapDownloading(input: InstallButtonStateInput, status: Status): InstallButtonState { + val fraction = input.progressPercent + ?.coerceIn(PROGRESS_MIN, PROGRESS_MAX) + ?.div(PROGRESS_MAX_FLOAT) + ?: 0f return InstallButtonState( - label = ButtonLabel( - resId = if (input.percentLabel == null) R.string.cancel else null, - text = input.percentLabel, - ), + label = ButtonLabel(resId = R.string.cancel), progressPercentText = input.percentLabel, + progressFraction = fraction, enabled = true, style = buildStyleFor(status, enabled = true), actionIntent = InstallButtonAction.CancelDownload, @@ -216,3 +231,7 @@ private fun buildStyleFor(status: Status, enabled: Boolean): InstallButtonStyle else -> InstallButtonStyle.Disabled } } + +private const val PROGRESS_MIN = 0 +private const val PROGRESS_MAX = 100 +private const val PROGRESS_MAX_FLOAT = 100f diff --git a/app/src/main/java/foundation/e/apps/ui/search/v2/SearchFragmentV2.kt b/app/src/main/java/foundation/e/apps/ui/search/v2/SearchFragmentV2.kt index 3e472f97c..cc68ad745 100644 --- a/app/src/main/java/foundation/e/apps/ui/search/v2/SearchFragmentV2.kt +++ b/app/src/main/java/foundation/e/apps/ui/search/v2/SearchFragmentV2.kt @@ -48,9 +48,11 @@ import foundation.e.apps.ui.AppProgressViewModel import foundation.e.apps.ui.MainActivityViewModel import foundation.e.apps.ui.application.subFrags.ApplicationDialogFragment import foundation.e.apps.ui.compose.screens.SearchScreen +import foundation.e.apps.ui.compose.state.ButtonLabel import foundation.e.apps.ui.compose.state.InstallButtonAction import foundation.e.apps.ui.compose.state.InstallButtonState import foundation.e.apps.ui.compose.state.InstallButtonStateInput +import foundation.e.apps.ui.compose.state.InstallButtonStyle import foundation.e.apps.ui.compose.state.PurchaseState import foundation.e.apps.ui.compose.state.mapAppToInstallState import foundation.e.apps.ui.compose.theme.AppTheme @@ -101,16 +103,20 @@ class SearchFragmentV2 : Fragment(R.layout.fragment_search_v2) { val downloadProgress by appProgressViewModel.downloadProgress.observeAsState() val progressPercentMap by searchViewModel.progressPercentByKey.collectAsState() val statusByKey by searchViewModel.statusByKey.collectAsState() + val pendingInstalls by searchViewModel.pendingInstalls.collectAsState() val selfPackageName = requireContext().packageName DownloadProgressEffect(downloadProgress) val installButtonStateProvider = buildInstallButtonStateProvider( - user = user, - isAnonymous = isAnonymous, - progressPercentMap = progressPercentMap, - statusByKey = statusByKey, - selfPackageName = selfPackageName, + InstallButtonProviderParams( + user = user, + isAnonymous = isAnonymous, + progressPercentMap = progressPercentMap, + statusByKey = statusByKey, + pendingInstalls = pendingInstalls, + selfPackageName = selfPackageName, + ) ) SearchScreen( @@ -148,33 +154,41 @@ class SearchFragmentV2 : Fragment(R.layout.fragment_search_v2) { } private fun buildInstallButtonStateProvider( - user: User, - isAnonymous: Boolean, - progressPercentMap: Map, - statusByKey: Map, - selfPackageName: String, + params: InstallButtonProviderParams, ): (Application) -> InstallButtonState { return { app -> val progressKey = progressKeyFor(app) - val progressPercent = progressPercentMap[progressKey] - val overrideStatus = statusByKey[progressKey] + val progressPercent = params.progressPercentMap[progressKey] + val overrideStatus = params.statusByKey[progressKey] + val isPending = progressKey in params.pendingInstalls val purchaseState = purchaseStateFor(app) val isBlocked = appInfoFetchViewModel.isAppInBlockedList(app) val isUnsupported = isUnsupportedApp(app) - mapInstallButtonState( - app = app, - installButtonContext = InstallButtonContext( - user = user, - isAnonymous = isAnonymous, - isUnsupported = isUnsupported, - purchaseState = purchaseState, - progressPercent = progressPercent, - overrideStatus = overrideStatus, - isBlocked = isBlocked, - selfPackageName = selfPackageName, + // Show disabled state while waiting for install to register + if (isPending && (overrideStatus == null || overrideStatus == Status.UNAVAILABLE)) { + InstallButtonState( + label = ButtonLabel(), + enabled = false, + style = InstallButtonStyle.AccentOutline, + showProgressBar = true, + actionIntent = InstallButtonAction.NoOp, ) - ) + } else { + mapInstallButtonState( + app = app, + installButtonContext = InstallButtonContext( + user = params.user, + isAnonymous = params.isAnonymous, + isUnsupported = isUnsupported, + purchaseState = purchaseState, + progressPercent = progressPercent, + overrideStatus = overrideStatus, + isBlocked = isBlocked, + selfPackageName = params.selfPackageName, + ) + ) + } } } @@ -234,6 +248,15 @@ class SearchFragmentV2 : Fragment(R.layout.fragment_search_v2) { val selfPackageName: String, ) + private data class InstallButtonProviderParams( + val user: User, + val isAnonymous: Boolean, + val progressPercentMap: Map, + val statusByKey: Map, + val pendingInstalls: Set, + val selfPackageName: String, + ) + private fun copyProgress(progress: DownloadProgress): DownloadProgress { return DownloadProgress( totalSizeBytes = progress.totalSizeBytes.toMutableMap(), @@ -247,15 +270,20 @@ class SearchFragmentV2 : Fragment(R.layout.fragment_search_v2) { when (action) { InstallButtonAction.Install, InstallButtonAction.UpdateSelfConfirm -> { + searchViewModel.markPendingInstall(app) mainActivityViewModel.verifyUiFilter(app) { if (mainActivityViewModel.shouldShowPaidAppsSnackBar(app)) { + searchViewModel.clearPendingInstall(app) return@verifyUiFilter } mainActivityViewModel.getApplication(app) } } - InstallButtonAction.CancelDownload -> mainActivityViewModel.cancelDownload(app) + InstallButtonAction.CancelDownload -> { + searchViewModel.clearPendingInstall(app) + mainActivityViewModel.cancelDownload(app) + } InstallButtonAction.OpenAppOrPwa -> { if (app.is_pwa) { mainActivityViewModel.launchPwa(app) diff --git a/app/src/main/java/foundation/e/apps/ui/search/v2/SearchViewModelV2.kt b/app/src/main/java/foundation/e/apps/ui/search/v2/SearchViewModelV2.kt index b093d55ee..c209b8ae6 100644 --- a/app/src/main/java/foundation/e/apps/ui/search/v2/SearchViewModelV2.kt +++ b/app/src/main/java/foundation/e/apps/ui/search/v2/SearchViewModelV2.kt @@ -79,7 +79,7 @@ data class ScrollPosition( ) @HiltViewModel -@Suppress("LongParameterList") +@Suppress("LongParameterList", "TooManyFunctions") class SearchViewModelV2 @Inject constructor( private val appLoungePreference: AppLoungePreference, cleanApkSearchPagingUseCase: CleanApkSearchPagingUseCase, @@ -110,6 +110,9 @@ class SearchViewModelV2 @Inject constructor( private val _statusByKey = MutableStateFlow>(emptyMap()) val statusByKey: StateFlow> = _statusByKey.asStateFlow() + private val _pendingInstalls = MutableStateFlow>(emptySet()) + val pendingInstalls: StateFlow> = _pendingInstalls.asStateFlow() + val fossPagingFlow = cleanApkSearchPagingUseCase( requests = searchRequests, source = Source.OPEN_SOURCE, @@ -340,6 +343,19 @@ class SearchViewModelV2 @Inject constructor( _statusByKey.update { current -> if (current[key] != app.status) current + (key to app.status) else current } + if (app.status != Status.UNAVAILABLE) { + _pendingInstalls.update { it - key } + } + } + + fun markPendingInstall(app: Application) { + val key = keyFor(app) + _pendingInstalls.update { it + key } + } + + fun clearPendingInstall(app: Application) { + val key = keyFor(app) + _pendingInstalls.update { it - key } } private fun keyFor(app: Application): String { diff --git a/app/src/test/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapperTest.kt b/app/src/test/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapperTest.kt index f81b483da..d7683f9a6 100644 --- a/app/src/test/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapperTest.kt +++ b/app/src/test/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapperTest.kt @@ -183,14 +183,15 @@ class InstallButtonStateMapperTest { } @Test - fun downloading_with_progress_shows_percent_and_cancel_intent() { + fun downloading_with_progress_shows_cancel_label_and_progress_fraction() { val state = mapAppToInstallState( input = defaultInput( app = baseApp(Status.DOWNLOADING), progressPercent = PROGRESS_PERCENT_VALID, ), ) - assertEquals("${PROGRESS_PERCENT_VALID}%", state.label.text) + assertEquals(R.string.cancel, state.label.resId) + assertEquals(PROGRESS_PERCENT_VALID / 100f, state.progressFraction) assertEquals(InstallButtonAction.CancelDownload, state.actionIntent) assertEquals(StatusTag.Downloading, state.statusTag) } -- GitLab From c1efcfb581fa82ba1b4025c270ce55fdbbdf9b16 Mon Sep 17 00:00:00 2001 From: Saalim Quadri Date: Fri, 13 Feb 2026 04:33:56 +0530 Subject: [PATCH 09/22] feat: Fixup search List state Signed-off-by: Saalim Quadri --- .../e/apps/ui/search/v2/SearchViewModelV2.kt | 5 ++++- .../e/apps/ui/search/v2/SearchViewModelV2Test.kt | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/apps/ui/search/v2/SearchViewModelV2.kt b/app/src/main/java/foundation/e/apps/ui/search/v2/SearchViewModelV2.kt index c209b8ae6..a152850ff 100644 --- a/app/src/main/java/foundation/e/apps/ui/search/v2/SearchViewModelV2.kt +++ b/app/src/main/java/foundation/e/apps/ui/search/v2/SearchViewModelV2.kt @@ -144,7 +144,10 @@ class SearchViewModelV2 @Inject constructor( fun onQueryChanged(newQuery: String) { _uiState.update { current -> - current.copy(query = newQuery) + current.copy( + query = newQuery, + hasSubmittedSearch = if (newQuery.isNotBlank()) false else current.hasSubmittedSearch, + ) } suggestionJob?.cancel() diff --git a/app/src/test/java/foundation/e/apps/ui/search/v2/SearchViewModelV2Test.kt b/app/src/test/java/foundation/e/apps/ui/search/v2/SearchViewModelV2Test.kt index 37e54d24c..f403ea961 100644 --- a/app/src/test/java/foundation/e/apps/ui/search/v2/SearchViewModelV2Test.kt +++ b/app/src/test/java/foundation/e/apps/ui/search/v2/SearchViewModelV2Test.kt @@ -206,6 +206,18 @@ class SearchViewModelV2Test { assertEquals("", state.query) } + @Test + fun `typing after submit resets hasSubmittedSearch`() = runTest { + viewModel.onSearchSubmitted("query") + assertTrue(viewModel.uiState.value.hasSubmittedSearch) + + viewModel.onQueryChanged("new") + + val state = viewModel.uiState.value + assertFalse(state.hasSubmittedSearch) + assertEquals("new", state.query) + } + @Test fun `clear query after submit retains tabs and results`() = runTest { viewModel.onSearchSubmitted("query") -- GitLab From 0697e6a4babb6c46b870861c4a3b2c9859941c93 Mon Sep 17 00:00:00 2001 From: Saalim Quadri Date: Fri, 13 Feb 2026 19:04:33 +0530 Subject: [PATCH 10/22] fix: Match progressIndicator on main tab screen with our accent Signed-off-by: Saalim Quadri --- .../e/apps/ui/compose/components/SearchResultsContent.kt | 9 +++++++-- .../e/apps/ui/compose/components/search/SearchLoading.kt | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt index 7cb9b0178..c910d04ac 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt @@ -30,6 +30,7 @@ import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -382,7 +383,10 @@ private fun PagingPlayStoreResultList( .padding(vertical = 16.dp), contentAlignment = Alignment.Center ) { - CircularProgressIndicator(modifier = Modifier.size(24.dp)) + CircularProgressIndicator( + modifier = Modifier.size(24.dp), + color = MaterialTheme.colorScheme.tertiary, + ) } } } @@ -528,7 +532,8 @@ private fun PagingSearchResultList( CircularProgressIndicator( modifier = Modifier .size(24.dp) - .testTag(SearchResultsContentTestTags.APPEND_LOADER) + .testTag(SearchResultsContentTestTags.APPEND_LOADER), + color = MaterialTheme.colorScheme.tertiary, ) } } diff --git a/app/src/main/java/foundation/e/apps/ui/compose/components/search/SearchLoading.kt b/app/src/main/java/foundation/e/apps/ui/compose/components/search/SearchLoading.kt index 89fd22650..72ef24ee3 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/components/search/SearchLoading.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/components/search/SearchLoading.kt @@ -21,6 +21,7 @@ package foundation.e.apps.ui.compose.components.search import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import foundation.e.apps.data.application.data.Application @@ -35,7 +36,7 @@ fun SearchShimmerList(modifier: Modifier = Modifier) { .fillMaxSize(), contentAlignment = androidx.compose.ui.Alignment.Center ) { - CircularProgressIndicator() + CircularProgressIndicator(color = MaterialTheme.colorScheme.tertiary) } } -- GitLab From 26e4e2db0293d514c7d92d731d9052a9fe210737 Mon Sep 17 00:00:00 2001 From: Saalim Quadri Date: Tue, 17 Feb 2026 11:56:58 +0530 Subject: [PATCH 11/22] fix: Align button with M2 Signed-off-by: Saalim Quadri --- .../components/SearchResultListItem.kt | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt index f32d37fba..889a58f6c 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt @@ -26,6 +26,7 @@ import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -54,6 +55,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import coil.compose.rememberImagePainter import foundation.e.apps.R import foundation.e.apps.data.application.data.Application @@ -118,22 +120,18 @@ fun SearchResultListItem( overflow = TextOverflow.Ellipsis, ) - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(6.dp), - ) { - if (uiState.showRating) { - RatingChip(ratingText = uiState.ratingText) - } else { - // keep layout predictable; hide rating when absent - Spacer(modifier = Modifier.width(0.dp)) - } + if (uiState.showRating || uiState.showSourceTag) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(6.dp), + ) { + if (uiState.showRating) { + RatingChip(ratingText = uiState.ratingText) + } - if (uiState.showSourceTag) { - SourceTag(text = uiState.sourceTag) - } else { - // design PNG omits source tag; kept togglable for legacy parity - Spacer(modifier = Modifier.width(0.dp)) + if (uiState.showSourceTag) { + SourceTag(text = uiState.sourceTag) + } } } } @@ -274,7 +272,10 @@ private fun PrimaryActionArea( return } - Column(horizontalAlignment = Alignment.End) { + Column( + horizontalAlignment = Alignment.End, + verticalArrangement = Arrangement.Center, + ) { val accentColor = MaterialTheme.colorScheme.tertiary val labelTextColor = when { uiState.isFilledStyle -> Color.White @@ -297,6 +298,7 @@ private fun PrimaryActionArea( maxLines = 1, overflow = TextOverflow.Clip, color = labelTextColor, + letterSpacing = 1.5.sp ) } } @@ -311,7 +313,7 @@ private fun PrimaryActionArea( enabled = uiState.enabled, modifier = Modifier .widthIn(min = 88.dp) - .height(40.dp) + .height(30.dp) .testTag(SearchResultListItemTestTags.PRIMARY_BUTTON), shape = RoundedCornerShape(4.dp), colors = ButtonDefaults.buttonColors( @@ -327,7 +329,7 @@ private fun PrimaryActionArea( disabledContentColor = labelTextColor.copy(alpha = 0.38f), ), border = BorderStroke(1.dp, borderColor), - contentPadding = ButtonDefaults.ContentPadding, + contentPadding = PaddingValues.Zero, ) { buttonContent() } -- GitLab From a238f319bada15500773fadbdc40b91ede932add Mon Sep 17 00:00:00 2001 From: Saalim Quadri Date: Tue, 17 Feb 2026 13:10:05 +0530 Subject: [PATCH 12/22] fix: source: Remove privacyScore and sourceTag Signed-off-by: Saalim Quadri --- .../components/SearchResultListItemTest.kt | 54 +-------- .../components/SearchResultListItem.kt | 113 +----------------- .../components/SearchResultsContent.kt | 22 ---- .../components/search/SearchLoading.kt | 6 - .../e/apps/ui/compose/screens/SearchScreen.kt | 2 - 5 files changed, 5 insertions(+), 192 deletions(-) diff --git a/app/src/androidTest/java/foundation/e/apps/ui/compose/components/SearchResultListItemTest.kt b/app/src/androidTest/java/foundation/e/apps/ui/compose/components/SearchResultListItemTest.kt index 0a538c4ce..081ef5f5d 100644 --- a/app/src/androidTest/java/foundation/e/apps/ui/compose/components/SearchResultListItemTest.kt +++ b/app/src/androidTest/java/foundation/e/apps/ui/compose/components/SearchResultListItemTest.kt @@ -54,7 +54,6 @@ class SearchResultListItemTest { onItemClick = {}, onPrimaryActionClick = {}, onShowMoreClick = {}, - onPrivacyClick = {}, ) } } @@ -70,7 +69,6 @@ class SearchResultListItemTest { fun metadataAndClicks_areWiredCorrectly() { var itemClicks = 0 var primaryClicks = 0 - var privacyClicks = 0 composeRule.setContent { AppTheme(darkTheme = false) { @@ -81,11 +79,6 @@ class SearchResultListItemTest { author = "Signal LLC", ratingText = "4.5", showRating = true, - sourceTag = "Play Store", - showSourceTag = true, - privacyScore = "06/10", - showPrivacyScore = true, - isPrivacyLoading = false, primaryAction = PrimaryActionUiState( label = "Install", enabled = true, @@ -96,7 +89,6 @@ class SearchResultListItemTest { onItemClick = { itemClicks += 1 }, onPrimaryActionClick = { primaryClicks += 1 }, onShowMoreClick = {}, - onPrivacyClick = { privacyClicks += 1 }, ) } } @@ -105,9 +97,7 @@ class SearchResultListItemTest { composeRule.onNodeWithText("Signal").assertIsDisplayed() composeRule.onNodeWithText("Signal LLC").assertIsDisplayed() composeRule.onNodeWithText("4.5").assertIsDisplayed() - composeRule.onNodeWithText("Play Store").assertIsDisplayed() composeRule.onNodeWithText("Install").assertIsDisplayed() - composeRule.onNodeWithText("06/10").assertIsDisplayed() composeRule.onAllNodesWithTag(SearchResultListItemTestTags.SHOW_MORE) .assertCountEquals(0) @@ -115,18 +105,15 @@ class SearchResultListItemTest { .performClick() composeRule.onNodeWithTag(SearchResultListItemTestTags.PRIMARY_BUTTON) .performClick() - composeRule.onNodeWithTag(SearchResultListItemTestTags.PRIVACY_BADGE) - .performClick() composeRule.runOnIdle { assertEquals(1, itemClicks) assertEquals(1, primaryClicks) - assertEquals(1, privacyClicks) } } @Test - fun hidesRatingAndSourceTag_whenDisabled() { + fun hidesRating_whenDisabled() { composeRule.setContent { AppTheme(darkTheme = false) { Surface(color = MaterialTheme.colorScheme.background) { @@ -136,11 +123,6 @@ class SearchResultListItemTest { author = "Anonymous", ratingText = "4.9", showRating = false, - sourceTag = "Play Store", - showSourceTag = false, - privacyScore = "", - showPrivacyScore = false, - isPrivacyLoading = false, primaryAction = PrimaryActionUiState( label = "Install", enabled = true, @@ -151,14 +133,12 @@ class SearchResultListItemTest { onItemClick = {}, onPrimaryActionClick = {}, onShowMoreClick = {}, - onPrivacyClick = {}, ) } } } composeRule.onAllNodesWithText("4.9").assertCountEquals(0) - composeRule.onAllNodesWithText("Play Store").assertCountEquals(0) } @Test @@ -175,11 +155,6 @@ class SearchResultListItemTest { author = "Author", ratingText = "", showRating = false, - sourceTag = "", - showSourceTag = false, - privacyScore = "", - showPrivacyScore = false, - isPrivacyLoading = false, primaryAction = PrimaryActionUiState( label = "Install", enabled = true, @@ -191,7 +166,6 @@ class SearchResultListItemTest { onItemClick = {}, onPrimaryActionClick = {}, onShowMoreClick = { showMoreClicks += 1 }, - onPrivacyClick = {}, ) } } @@ -210,7 +184,7 @@ class SearchResultListItemTest { } @Test - fun inProgressPrimaryAction_andPrivacyLoading_showSpinners() { + fun inProgressPrimaryAction_showsSpinner() { composeRule.setContent { AppTheme(darkTheme = false) { Surface(color = MaterialTheme.colorScheme.background) { @@ -220,11 +194,6 @@ class SearchResultListItemTest { author = "Author", ratingText = "", showRating = false, - sourceTag = "", - showSourceTag = false, - privacyScore = "07/10", - showPrivacyScore = true, - isPrivacyLoading = true, primaryAction = PrimaryActionUiState( label = "", enabled = true, @@ -235,7 +204,6 @@ class SearchResultListItemTest { onItemClick = {}, onPrimaryActionClick = {}, onShowMoreClick = {}, - onPrivacyClick = {}, ) } } @@ -243,9 +211,6 @@ class SearchResultListItemTest { composeRule.onNodeWithTag(SearchResultListItemTestTags.PRIMARY_PROGRESS) .assertIsDisplayed() - composeRule.onNodeWithTag(SearchResultListItemTestTags.PRIVACY_PROGRESS) - .assertIsDisplayed() - composeRule.onAllNodesWithText("07/10").assertCountEquals(0) } private fun sampleApp(name: String) = Application(name = name) @@ -254,11 +219,6 @@ class SearchResultListItemTest { author = "", ratingText = "", showRating = false, - sourceTag = "", - showSourceTag = false, - privacyScore = "", - showPrivacyScore = false, - isPrivacyLoading = false, primaryAction = PrimaryActionUiState( label = "", enabled = false, @@ -274,21 +234,11 @@ class SearchResultListItemTest { author: String, ratingText: String, showRating: Boolean, - sourceTag: String, - showSourceTag: Boolean, - privacyScore: String, - showPrivacyScore: Boolean, - isPrivacyLoading: Boolean, primaryAction: PrimaryActionUiState, ): SearchResultListItemState = SearchResultListItemState( author = author, ratingText = ratingText, showRating = showRating, - sourceTag = sourceTag, - showSourceTag = showSourceTag, - privacyScore = privacyScore, - showPrivacyScore = showPrivacyScore, - isPrivacyLoading = isPrivacyLoading, primaryAction = primaryAction, iconUrl = null, placeholderResId = null, diff --git a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt index 889a58f6c..ac9e8b32d 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt @@ -69,7 +69,6 @@ fun SearchResultListItem( onItemClick: (Application) -> Unit, onPrimaryActionClick: (Application) -> Unit, onShowMoreClick: (Application) -> Unit, - onPrivacyClick: (Application) -> Unit, modifier: Modifier = Modifier, ) { if (uiState.isPlaceholder) { @@ -120,19 +119,8 @@ fun SearchResultListItem( overflow = TextOverflow.Ellipsis, ) - if (uiState.showRating || uiState.showSourceTag) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(6.dp), - ) { - if (uiState.showRating) { - RatingChip(ratingText = uiState.ratingText) - } - - if (uiState.showSourceTag) { - SourceTag(text = uiState.sourceTag) - } - } + if (uiState.showRating) { + RatingChip(ratingText = uiState.ratingText) } } @@ -140,10 +128,6 @@ fun SearchResultListItem( uiState = uiState.primaryAction, onPrimaryClick = { onPrimaryActionClick(application) }, onShowMoreClick = { onShowMoreClick(application) }, - privacyScore = uiState.privacyScore, - showPrivacyScore = uiState.showPrivacyScore, - isPrivacyLoading = uiState.isPrivacyLoading, - onPrivacyClick = { onPrivacyClick(application) }, ) } } @@ -190,75 +174,11 @@ private fun RatingChip(ratingText: String) { } } -@Composable -private fun SourceTag(text: String) { - Text( - text = text, - style = MaterialTheme.typography.labelMedium, - color = MaterialTheme.colorScheme.onSecondaryContainer, - modifier = Modifier - .background( - color = MaterialTheme.colorScheme.secondaryContainer, - shape = MaterialTheme.shapes.small, - ) - .padding(horizontal = 8.dp, vertical = 4.dp), - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) -} - -@Composable -private fun PrivacyBadge( - privacyScore: String, - isVisible: Boolean, - isLoading: Boolean, - onClick: () -> Unit, -) { - if (!isVisible) { - return - } else { - // proceed to render the badge - } - - Row( - verticalAlignment = Alignment.CenterVertically, - modifier = Modifier - .testTag(SearchResultListItemTestTags.PRIVACY_BADGE) - .clickable(onClick = onClick), - ) { - Image( - painter = painterResource(id = R.drawable.ic_lock), - contentDescription = stringResource(id = R.string.privacy_score), - modifier = Modifier.size(16.dp), - ) - Spacer(modifier = Modifier.width(4.dp)) - if (isLoading) { - CircularProgressIndicator( - modifier = Modifier - .size(16.dp) - .testTag(SearchResultListItemTestTags.PRIVACY_PROGRESS), - strokeWidth = 2.dp, - color = MaterialTheme.colorScheme.tertiary, - ) - } else { - Text( - text = privacyScore, - style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.onBackground, - ) - } - } -} - @Composable private fun PrimaryActionArea( uiState: PrimaryActionUiState, onPrimaryClick: () -> Unit, onShowMoreClick: () -> Unit, - privacyScore: String, - showPrivacyScore: Boolean, - isPrivacyLoading: Boolean, - onPrivacyClick: () -> Unit, ) { if (uiState.showMore) { Text( @@ -333,16 +253,6 @@ private fun PrimaryActionArea( ) { buttonContent() } - - if (showPrivacyScore) { - Spacer(modifier = Modifier.height(8.dp)) - PrivacyBadge( - privacyScore = privacyScore, - isVisible = true, - isLoading = isPrivacyLoading, - onClick = onPrivacyClick, - ) - } } } @@ -363,11 +273,6 @@ data class SearchResultListItemState( val author: String, val ratingText: String, val showRating: Boolean, - val sourceTag: String, - val showSourceTag: Boolean, - val privacyScore: String, - val showPrivacyScore: Boolean, - val isPrivacyLoading: Boolean, val primaryAction: PrimaryActionUiState, val iconUrl: String? = null, val placeholderResId: Int?, @@ -390,8 +295,6 @@ internal object SearchResultListItemTestTags { const val SHOW_MORE = "search_result_item_show_more" const val PRIMARY_BUTTON = "search_result_item_primary_button" const val PRIMARY_PROGRESS = "search_result_item_primary_progress" - const val PRIVACY_BADGE = "search_result_item_privacy_badge" - const val PRIVACY_PROGRESS = "search_result_item_privacy_progress" } // --- Previews --- @@ -404,8 +307,7 @@ private fun SearchResultListItemPreviewInstall() { SearchResultListItem( application = sampleApp(name = "iMe: AI Messenger"), uiState = sampleState( - rating = "4.4", - privacy = "06/10", + rating = "4.3", primary = PrimaryActionUiState( label = "Install", enabled = true, @@ -417,7 +319,6 @@ private fun SearchResultListItemPreviewInstall() { onItemClick = {}, onPrimaryActionClick = {}, onShowMoreClick = {}, - onPrivacyClick = {}, ) } } @@ -432,7 +333,6 @@ private fun SearchResultListItemPreviewOpen() { application = sampleApp(name = "This is a very long app name"), uiState = sampleState( rating = "4.3", - privacy = "10/10", primary = PrimaryActionUiState( label = "Open", enabled = true, @@ -444,7 +344,6 @@ private fun SearchResultListItemPreviewOpen() { onItemClick = {}, onPrimaryActionClick = {}, onShowMoreClick = {}, - onPrivacyClick = {}, ) } } @@ -455,18 +354,12 @@ private fun sampleApp(name: String) = Application(name = name) @Composable private fun sampleState( rating: String, - privacy: String, primary: PrimaryActionUiState, ): SearchResultListItemState = SearchResultListItemState( author = "This is a very long author name which can take multiple lines", ratingText = rating, showRating = true, - sourceTag = "Open-source", // PNG omits this; kept for legacy data - showSourceTag = true, - privacyScore = privacy, - showPrivacyScore = true, - isPrivacyLoading = false, primaryAction = primary, isPlaceholder = false, iconUrl = null, diff --git a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt index c910d04ac..2f3c4f8c1 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt @@ -77,7 +77,6 @@ fun SearchResultsContent( onResultClick: (Application) -> Unit = {}, onPrimaryActionClick: (Application, InstallButtonAction) -> Unit = { _, _ -> }, onShowMoreClick: (Application) -> Unit = {}, - onPrivacyClick: (Application) -> Unit = {}, installButtonStateProvider: (Application) -> InstallButtonState, ) { when { @@ -98,7 +97,6 @@ fun SearchResultsContent( onResultClick = onResultClick, onPrimaryActionClick = onPrimaryActionClick, onShowMoreClick = onShowMoreClick, - onPrivacyClick = onPrivacyClick, installButtonStateProvider = installButtonStateProvider, modifier = modifier.fillMaxSize(), ) @@ -162,7 +160,6 @@ fun SearchResultsContent( onResultClick = onResultClick, onPrimaryActionClick = onPrimaryActionClick, onShowMoreClick = onShowMoreClick, - onPrivacyClick = onPrivacyClick, installButtonStateProvider = installButtonStateProvider, modifier = Modifier.fillMaxSize(), ) @@ -184,7 +181,6 @@ private fun SearchTabPage( onResultClick: (Application) -> Unit, onPrimaryActionClick: (Application, InstallButtonAction) -> Unit, onShowMoreClick: (Application) -> Unit, - onPrivacyClick: (Application) -> Unit, installButtonStateProvider: (Application) -> InstallButtonState, modifier: Modifier = Modifier, ) { @@ -223,7 +219,6 @@ private fun SearchTabPage( onItemClick = onResultClick, onPrimaryActionClick = onPrimaryActionClick, onShowMoreClick = onShowMoreClick, - onPrivacyClick = onPrivacyClick, installButtonStateProvider = installButtonStateProvider, emptyResultsStringResource = emptyResultsStringResource, errorTitleStringResource = errorTitleStringResource, @@ -240,7 +235,6 @@ private fun SearchTabPage( onItemClick = onResultClick, onPrimaryActionClick = onPrimaryActionClick, onShowMoreClick = onShowMoreClick, - onPrivacyClick = onPrivacyClick, installButtonStateProvider = installButtonStateProvider, emptyResultsStringResource = emptyResultsStringResource, errorTitleStringResource = errorTitleStringResource, @@ -259,7 +253,6 @@ private fun PagingPlayStoreResultList( onItemClick: (Application) -> Unit, onPrimaryActionClick: (Application, InstallButtonAction) -> Unit, onShowMoreClick: (Application) -> Unit, - onPrivacyClick: (Application) -> Unit, installButtonStateProvider: (Application) -> InstallButtonState, emptyResultsStringResource: Int, errorTitleStringResource: Int, @@ -367,7 +360,6 @@ private fun PagingPlayStoreResultList( ) }, onShowMoreClick = onShowMoreClick, - onPrivacyClick = onPrivacyClick, modifier = Modifier.fillMaxWidth(), ) } else { @@ -406,7 +398,6 @@ private fun PagingSearchResultList( onItemClick: (Application) -> Unit, onPrimaryActionClick: (Application, InstallButtonAction) -> Unit, onShowMoreClick: (Application) -> Unit, - onPrivacyClick: (Application) -> Unit, installButtonStateProvider: (Application) -> InstallButtonState, emptyResultsStringResource: Int, errorTitleStringResource: Int, @@ -513,7 +504,6 @@ private fun PagingSearchResultList( ) }, onShowMoreClick = onShowMoreClick, - onPrivacyClick = onPrivacyClick, modifier = Modifier.fillMaxWidth(), ) } else { @@ -551,11 +541,6 @@ private fun Application.toSearchResultUiState(buttonState: InstallButtonState): author = "", ratingText = "", showRating = false, - sourceTag = "", - showSourceTag = false, - privacyScore = "", - showPrivacyScore = false, - isPrivacyLoading = false, primaryAction = PrimaryActionUiState( label = "", enabled = false, @@ -579,17 +564,10 @@ private fun Application.toSearchResultUiState(buttonState: InstallButtonState): else -> stringResource(id = R.string.not_available) } - val sourceTagText = source.toString() - return SearchResultListItemState( author = author.ifBlank { package_name }, ratingText = ratingText, showRating = ratingText.isNotBlank(), - sourceTag = sourceTagText, - showSourceTag = false, - privacyScore = "", - showPrivacyScore = false, // Privacy scores are disabled on Search per functional spec. - isPrivacyLoading = false, primaryAction = PrimaryActionUiState( label = buttonState.label.text ?: buttonState.progressPercentText diff --git a/app/src/main/java/foundation/e/apps/ui/compose/components/search/SearchLoading.kt b/app/src/main/java/foundation/e/apps/ui/compose/components/search/SearchLoading.kt index 72ef24ee3..ca86e1760 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/components/search/SearchLoading.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/components/search/SearchLoading.kt @@ -48,7 +48,6 @@ fun SearchResultListItemPlaceholder(modifier: Modifier = Modifier) { onItemClick = {}, onPrimaryActionClick = {}, onShowMoreClick = {}, - onPrivacyClick = {}, modifier = modifier ) } @@ -57,11 +56,6 @@ private fun placeholderState() = SearchResultListItemState( author = "", ratingText = "", showRating = false, - sourceTag = "", - showSourceTag = false, - privacyScore = "", - showPrivacyScore = false, - isPrivacyLoading = false, primaryAction = PrimaryActionUiState( label = "", enabled = false, diff --git a/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchScreen.kt b/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchScreen.kt index 5b74ad295..9f7898a4f 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchScreen.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/screens/SearchScreen.kt @@ -77,7 +77,6 @@ fun SearchScreen( onScrollPositionChange: (SearchTabType, Int, Int) -> Unit = { _, _, _ -> }, onResultClick: (Application) -> Unit = {}, onShowMoreClick: (Application) -> Unit = {}, - onPrivacyClick: (Application) -> Unit = {}, onPrimaryAction: (Application, InstallButtonAction) -> Unit = { _, _ -> }, installButtonStateProvider: (Application) -> InstallButtonState, ) { @@ -158,7 +157,6 @@ fun SearchScreen( onResultClick = onResultClick, onPrimaryActionClick = onPrimaryAction, onShowMoreClick = onShowMoreClick, - onPrivacyClick = onPrivacyClick, installButtonStateProvider = installButtonStateProvider, ) } -- GitLab From 1620d0c1503d8b2cdbedea3d3f8564d13f8a0ac7 Mon Sep 17 00:00:00 2001 From: Saalim Quadri Date: Mon, 9 Feb 2026 14:05:57 +0530 Subject: [PATCH 13/22] feat: Select new SearchScreen Signed-off-by: Saalim Quadri --- app/src/main/res/menu/navigation_menu.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/menu/navigation_menu.xml b/app/src/main/res/menu/navigation_menu.xml index 9b412b814..885eeaff7 100644 --- a/app/src/main/res/menu/navigation_menu.xml +++ b/app/src/main/res/menu/navigation_menu.xml @@ -30,7 +30,7 @@ android:title="@string/menu_categories" /> -- GitLab From 00529f81acda927e1c81d027a577f17b4684b6f4 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Wed, 11 Feb 2026 17:32:37 +0600 Subject: [PATCH 14/22] fix(ui): align install button's text capitalization and styling Install/action button in Home, Categories, Search and Updates screen now follows the capitalization rule with only first letter being capital. Styles of the button is also streamlined to a single style. Signed-off-by: Saalim Quadri --- app/src/main/res/layout/application_list_item.xml | 7 ------- .../res/layout/fragment_application_download.xml | 11 ++--------- app/src/main/res/layout/home_child_list_item.xml | 8 +------- app/src/main/res/values/themes.xml | 13 ++++++++++--- 4 files changed, 13 insertions(+), 26 deletions(-) diff --git a/app/src/main/res/layout/application_list_item.xml b/app/src/main/res/layout/application_list_item.xml index 97a97953b..5730547c9 100644 --- a/app/src/main/res/layout/application_list_item.xml +++ b/app/src/main/res/layout/application_list_item.xml @@ -131,14 +131,7 @@ + android:text="@string/install" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/home_child_list_item.xml b/app/src/main/res/layout/home_child_list_item.xml index cfb79c302..d75ac853f 100644 --- a/app/src/main/res/layout/home_child_list_item.xml +++ b/app/src/main/res/layout/home_child_list_item.xml @@ -66,14 +66,8 @@ + android:text="@string/install" /> - \ No newline at end of file + -- GitLab From 252432129fbe901ed03ed157137a0ed720915631 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Tue, 24 Feb 2026 22:06:36 +0600 Subject: [PATCH 15/22] refactor: add padding to install button UI for long button labels --- .../e/apps/ui/compose/components/SearchResultListItem.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt index ac9e8b32d..90d044761 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt @@ -215,6 +215,7 @@ private fun PrimaryActionArea( } else { Text( text = uiState.label, + modifier = Modifier.padding(horizontal = 4.dp), maxLines = 1, overflow = TextOverflow.Clip, color = labelTextColor, @@ -334,7 +335,7 @@ private fun SearchResultListItemPreviewOpen() { uiState = sampleState( rating = "4.3", primary = PrimaryActionUiState( - label = "Open", + label = "ThisIsALongButtonName", enabled = true, isInProgress = false, isFilledStyle = true, -- GitLab From bfd180a5ab5f5080b95b328f844fbce190eedc76 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Mon, 23 Feb 2026 13:42:48 +0600 Subject: [PATCH 16/22] refactor(ui): set disabled colour as install button's border for queued and awaiting status --- .../components/SearchResultListItem.kt | 6 ++++- .../components/SearchResultsContent.kt | 1 + .../compose/state/InstallButtonStateMapper.kt | 5 +++-- .../e/apps/ui/search/v2/SearchFragmentV2.kt | 4 ++-- .../state/InstallButtonStateMapperTest.kt | 22 ++++++++++++++++++- 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt index 90d044761..37f678dec 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt @@ -49,6 +49,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight @@ -61,6 +62,7 @@ import foundation.e.apps.R import foundation.e.apps.data.application.data.Application import foundation.e.apps.ui.compose.state.InstallButtonAction import foundation.e.apps.ui.compose.theme.AppTheme +import foundation.e.elib.R as eR @Composable fun SearchResultListItem( @@ -199,6 +201,7 @@ private fun PrimaryActionArea( val accentColor = MaterialTheme.colorScheme.tertiary val labelTextColor = when { uiState.isFilledStyle -> Color.White + uiState.isDisabledStyle -> colorResource(eR.color.e_disabled_color) else -> accentColor } @@ -226,6 +229,7 @@ private fun PrimaryActionArea( val borderColor = when { uiState.isFilledStyle -> Color.Transparent + uiState.isDisabledStyle -> colorResource(eR.color.e_disabled_color) uiState.enabled -> accentColor else -> accentColor.copy(alpha = 0.38f) } @@ -247,7 +251,6 @@ private fun PrimaryActionArea( uiState.isFilledStyle -> accentColor.copy(alpha = 0.12f) else -> Color.Transparent }, - disabledContentColor = labelTextColor.copy(alpha = 0.38f), ), border = BorderStroke(1.dp, borderColor), contentPadding = PaddingValues.Zero, @@ -285,6 +288,7 @@ data class PrimaryActionUiState( val enabled: Boolean, val isInProgress: Boolean, val isFilledStyle: Boolean, + val isDisabledStyle: Boolean = false, val showMore: Boolean = false, val actionIntent: InstallButtonAction = InstallButtonAction.NoOp, val progressFraction: Float = 0f, diff --git a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt index 2f3c4f8c1..0c7b428b7 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultsContent.kt @@ -576,6 +576,7 @@ private fun Application.toSearchResultUiState(buttonState: InstallButtonState): enabled = buttonState.enabled, isInProgress = buttonState.isInProgress(), isFilledStyle = buttonState.style == InstallButtonStyle.AccentFill, + isDisabledStyle = buttonState.style == InstallButtonStyle.Disabled, showMore = false, actionIntent = buttonState.actionIntent, progressFraction = buttonState.progressFraction, diff --git a/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt b/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt index 5df5c1117..cc407f11d 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt @@ -169,8 +169,8 @@ private fun mapDownloading(input: InstallButtonStateInput, status: Status): Inst private fun mapInstalling(status: Status): InstallButtonState { return InstallButtonState( label = ButtonLabel(resId = R.string.installing), - enabled = false, - style = buildStyleFor(status, enabled = false), + enabled = true, + style = buildStyleFor(status, enabled = true), actionIntent = InstallButtonAction.NoOp, statusTag = StatusTag.Installing, rawStatus = status, @@ -223,6 +223,7 @@ private fun buildDefaultBlockedLabel(app: Application): ButtonLabel { private fun buildStyleFor(status: Status, enabled: Boolean): InstallButtonStyle { return when { + status == Status.QUEUED || status == Status.AWAITING -> InstallButtonStyle.Disabled status == Status.INSTALLED || status == Status.UPDATABLE -> { if (enabled) InstallButtonStyle.AccentFill else InstallButtonStyle.Disabled } diff --git a/app/src/main/java/foundation/e/apps/ui/search/v2/SearchFragmentV2.kt b/app/src/main/java/foundation/e/apps/ui/search/v2/SearchFragmentV2.kt index cc68ad745..c9f2bd1e5 100644 --- a/app/src/main/java/foundation/e/apps/ui/search/v2/SearchFragmentV2.kt +++ b/app/src/main/java/foundation/e/apps/ui/search/v2/SearchFragmentV2.kt @@ -169,8 +169,8 @@ class SearchFragmentV2 : Fragment(R.layout.fragment_search_v2) { if (isPending && (overrideStatus == null || overrideStatus == Status.UNAVAILABLE)) { InstallButtonState( label = ButtonLabel(), - enabled = false, - style = InstallButtonStyle.AccentOutline, + enabled = true, + style = InstallButtonStyle.Disabled, showProgressBar = true, actionIntent = InstallButtonAction.NoOp, ) diff --git a/app/src/test/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapperTest.kt b/app/src/test/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapperTest.kt index d7683f9a6..59c242ede 100644 --- a/app/src/test/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapperTest.kt +++ b/app/src/test/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapperTest.kt @@ -205,6 +205,26 @@ class InstallButtonStateMapperTest { assertEquals(InstallButtonAction.CancelDownload, state.actionIntent) } + @Test + fun queued_maps_to_disabled_style() { + val state = mapAppToInstallState( + input = defaultInput(app = baseApp(Status.QUEUED)), + ) + assertEquals(R.string.cancel, state.label.resId) + assertEquals(InstallButtonStyle.Disabled, state.style) + assertTrue(state.enabled) + } + + @Test + fun awaiting_maps_to_disabled_style() { + val state = mapAppToInstallState( + input = defaultInput(app = baseApp(Status.AWAITING)), + ) + assertEquals(R.string.cancel, state.label.resId) + assertEquals(InstallButtonStyle.Disabled, state.style) + assertTrue(state.enabled) + } + @Test fun downloading_progress_below_zero_uses_cancel_label() { val state = mapAppToInstallState( @@ -235,7 +255,7 @@ class InstallButtonStateMapperTest { input = defaultInput(app = baseApp(Status.INSTALLING)), ) assertEquals(R.string.installing, state.label.resId) - assertFalse(state.enabled) + assertTrue(state.enabled) assertEquals(StatusTag.Installing, state.statusTag) } -- GitLab From 40b0d8338d4566537dcd464c1515dfa1ead2b722 Mon Sep 17 00:00:00 2001 From: Fahim Masud Choudhury Date: Tue, 24 Feb 2026 22:47:37 +0600 Subject: [PATCH 17/22] refactor: update wording from Common apps to Apps --- app/src/main/res/values-de/strings.xml | 4 ++-- app/src/main/res/values-es/strings.xml | 4 ++-- app/src/main/res/values-fi/strings.xml | 4 ++-- app/src/main/res/values-fr/strings.xml | 4 ++-- app/src/main/res/values-is/strings.xml | 4 ++-- app/src/main/res/values-it/strings.xml | 4 ++-- app/src/main/res/values-ja/strings.xml | 4 ++-- app/src/main/res/values-nb-rNO/strings.xml | 4 ++-- app/src/main/res/values-nl/strings.xml | 4 ++-- app/src/main/res/values-pt-rBR/strings.xml | 4 ++-- app/src/main/res/values-ru/strings.xml | 4 ++-- app/src/main/res/values-sk/strings.xml | 4 ++-- app/src/main/res/values-sv/strings.xml | 4 ++-- app/src/main/res/values-tr/strings.xml | 4 ++-- app/src/main/res/values-uk/strings.xml | 4 ++-- app/src/main/res/values/strings.xml | 4 ++-- app/src/main/res/xml/settings_preferences.xml | 2 +- 17 files changed, 33 insertions(+), 33 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index d999f1060..298307ec0 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -56,7 +56,7 @@ Benachrichtige, wenn App-Aktualisierungen verfügbar sind Zeige Anwendungen an: Zeige quelloffene Apps an - Zeige allgemeine Apps an + Zeige Apps an Zeige PWAs an Konto Nutzungsbedingungen @@ -213,7 +213,7 @@ Allgemeine Apps nicht verfügbar Quelloffene Apps und PWA nicht verfügbar - Beim Laden der allgemeinen Apps ist ein Fehler aufgetreten. Nur quelloffene Apps und PWA sind momentan verfügbar. + Beim Laden der Apps ist ein Fehler aufgetreten. Nur quelloffene Apps und Web Apps sind momentan verfügbar. Beim Laden von PWA und quelloffenen Apps ist ein Fehler aufgetreten. Nur allgemeine Apps sind momentan verfügbar. diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index c1bdd8417..23ece824b 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -70,7 +70,7 @@ Descargar e instalar actualizaciones en segundo plano Mostrar actualizaciones disponibles Mostrar aplicaciones: - Mostrar aplicaciones comunes + Mostrar Apps Mostrar aplicaciones de código abierto Mostrar PWA Cuenta @@ -212,7 +212,7 @@ Aplicaciones comunes no disponibles Aplicaciones de código abierto y PWA no disponibles - Se produjo un error al cargar las aplicaciones comunes. Solo aplicaciones de código abierto y PWA están disponibles por ahora. + Se produjo un error al cargar Apps. Solo aplicaciones de código abierto y Web Apps están disponibles por ahora. Hubo un error al cargar las aplicaciones PWA y de código abierto. Solo aplicaciones comunes están disponibles por ahora. App Lounge se cerrará durante la instalación de la actualización. Por favor, abstente de hacer nada en hasta que la actualización (descarga + instalación) haya terminado. Podrás usarla en un par de minutos como máximo. ¡Advertencia de actualización! diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index c33493739..f3da14a32 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -56,7 +56,7 @@ Tili Näytä PWAt Näytä avoimen lähdekoodin sovellukset - Näytä yleiset sovellukset + Näytä sovellukset Näytä sovellukset: Näytä ilmoitus kun sovelluspäivityksiä on saatavilla Näytä saatavilla olevat päivitykset @@ -168,7 +168,7 @@ Olet liian nuori asentaaksesi %1$s. Tarkista vanhemmaltasi että ikäryhmäsi on oikea, tai sammuta lapsilukko voidaksesi asentaa sen. Tässä sovelluksessa saattaa olla sopimatonta sisältöä. Tarkistetaan päivityksiä... - Yleisten sovellusten lataamisessa tapahtui virhe. Vain Avoimen lähdekoodin sovellukset ja PWA-sovellukset ovat saatavilla tällä hetkellä. + Sovellusten lataamisessa tapahtui virhe. Vain Avoimen lähdekoodin sovellukset ja Web Apps ovat saatavilla tällä hetkellä. Yleiset sovellukset ei saatavilla Tapahtui virhe ladattaessa PWA- ja Avoimen lähdekoodin sovelluksia. Vain Yleiset sovellukset ovat saatavilla tällä hetkellä. [%1$s] Rajoitettu sovellus diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index a1520b666..144da352c 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -38,7 +38,7 @@ Afficher les mises à jour disponibles Afficher une notification lorsque des mises à jour d\'applications sont disponibles Afficher les applications : - Afficher les applications répandues + Afficher les Apps Afficher les PWAs Compte Conditions de Service @@ -212,7 +212,7 @@ Applications communes indisponibles Applications Open Source et PWA indisponibles - Une erreur est survenue lors du chargement des applications communes. Seules les applications Open Source et PWA sont disponibles pour l’instant. + Une erreur est survenue lors du chargement des Apps. Seules les applications Open Source et les Web Apps sont disponibles pour l’instant. Une erreur est survenue lors du chargement des applications PWA et Open Source. Seules les applications communes sont disponibles pour l\'instant. App Lounge sera fermé pendant l\'installation de la mise à jour. Veuillez ne rien faire tant que la mise à jour (téléchargement + installation) n\'est pas terminée. Vous pourrez y accéder dans quelques minutes au maximum. diff --git a/app/src/main/res/values-is/strings.xml b/app/src/main/res/values-is/strings.xml index 2ad5a76f4..4ac0aa978 100644 --- a/app/src/main/res/values-is/strings.xml +++ b/app/src/main/res/values-is/strings.xml @@ -49,7 +49,7 @@ Birta tiltækar uppfærslur Birta tilkynningu þegar uppfærslur eru tiltækar Birta forrit: - Birta algeng forrit + Birta forrit Birta opinn hugbúnað Um hugbúnaðinn Útgáfa App Lounge @@ -194,7 +194,7 @@ Forrit með opnum grunnkóða og PWA óaðgengileg Villa kom upp við að hlaða inn forritum með opnum grunnkóða og PWA. Aðeins algeng forrit eru tiltæk í augnablikinu. Algeng forrit óaðgengileg - Villa kom upp við að hlaða inn algengum forritum. Aðeins forrit með opnum grunnkóða og PWA eru tiltæk í augnablikinu. + Villa kom upp við að hlaða inn forritum. Aðeins forrit með opnum grunnkóða og Web Apps eru tiltæk í augnablikinu. App Lounge verður lokað af kerfinu á meðan það uppfærir sjálft sig. Vertu helst ekki að gera neitt annað þangað til uppfærslu App Lounge er lokið. Það verður svo aðgengilegt aftur eftir örfáar mínútur. Veldu hvernig á að skrá þig inn diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 4197e28ea..c790787c9 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -70,7 +70,7 @@ Scarica ed installa gli aggiornamenti App in background Mostra gli aggiornamenti disponibili Mostra App: - Mostra tutte le App + Mostra App Mostra App open-source Mostra le PWA Account @@ -212,7 +212,7 @@ App comuni non disponibili App Open Source e PWA non disponibili - Si è verificato un errore durante il caricamento delle app comuni. Solo le app Open Source e PWA sono disponibili per ora. + Si è verificato un errore durante il caricamento delle App. Solo le app Open Source e le Web Apps sono disponibili per ora. Si è verificato un errore durante il caricamento delle app PWA e Open Source. Solo le app comuni sono disponibili per ora. Sto raccogliendo la valutazione di tutte le app che hai installato. L\'applicazione potrebbe contenere nudità, bestemmie, insulti, violenza, estrema sessualità, politicamente scorretto o altri argomenti potenzialmente disturbanti. Questo è rilevante specialmente in ambienti tipo lavoro, scuola, ambienti religiosi e familiari. diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index f5f0ed433..7e184bd66 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -111,7 +111,7 @@ 売上が上位のゲーム トレンド上位のアプリ トレンド上位のゲーム - 一般的なアプリを表示 + アプリを表示 一般的なアプリを表示するにはログインが必要です。 このアプリは後で利用可能になります! オープンソースのアプリのみが許可されている間はGoogle Playのアプリは表示できません。 @@ -187,7 +187,7 @@ インストール済みアプリのコンテンツ評価を取得中です。 一般アプリを利用できません オープンソースアプリと PWA を利用できません - 一般アプリの読み込み中にエラーが発生しました。現在はオープンソースアプリと PWA のみ利用できます。 + アプリの読み込み中にエラーが発生しました。現在はオープンソースアプリと Web Apps のみ利用できます。 PWA とオープンソースアプリの読み込み中にエラーが発生しました。現在は一般アプリのみ利用できます。 アプリは利用できません このアプリはインストールできません。これは通常、所在地(地域)やアカウントの年齢設定(年齢確認や年齢/コンテンツ評価を含む)に基づくコンテンツ制限が原因です。 diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index feea4829e..be7629088 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -139,7 +139,7 @@ Oppdater applikasjoner installert av andre butikker Oppdater applikasjoner som er installert fra andre app-butikker. \nSlike applikasjoner vil bli forsøkt oppdatert fra vanlige applikasjoner og kategorien åpen kildekode. - Vis vanlige applikasjoner + Vis applikasjoner Du må logge inn for å kunne se vanlige applikasjoner. Personvernscore Vurderinger @@ -192,7 +192,7 @@ Samler innholdsvurdering for alle applikasjonene du har installert. Vanlige applikasjoner er ikke tilgjengelige Åpen kildekode-applikasjoner og PWA er ikke tilgjengelige - Det oppstod en feil under innlasting av en applikasjon. Bare åpen kildekode-applikasjoner og PWA er tilgjengelige for øyeblikket. + Det oppstod en feil under innlasting av applikasjoner. Bare åpen kildekode-applikasjoner og Web Apps er tilgjengelige for øyeblikket. Det oppstod en feil under innlasting av PWA- og åpen kildekode-applikasjoner. Bare vanlige applikasjoner er tilgjengelige for øyeblikket. Advarsel om oppdatering! diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index ae1a93a4d..bc44312da 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -97,7 +97,7 @@ Over Toon PWA\'s Toon open source apps - Toon algemene apps + Toon apps Toon applicaties: Toon een melding wanneer er app updates beschikbaar zijn Toon beschikbare updates @@ -193,7 +193,7 @@ Attentie, update! Algemene apps niet beschikbaar Open source apps en PWA niet beschikbaar - Er is een fout opgetreden tijdens het laden van de algemene apps. Enkel opensource apps en PWA\'s zijn beschikbaar. + Er is een fout opgetreden tijdens het laden van apps. Enkel opensource apps en Web Apps zijn beschikbaar. Er is een fout opgetreden tijdens het laden van PWA en opensource apps. Enkel algemene apps zijn beschikbaar. App Lounge zal afgesloten worden tijdens de update. Voer a.u.b. geen andere taken uit totdat de update is voltooid (download + installatie). Binnen maximum enkele minuten zal je terug toegang hebben. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 210f22403..0dcadf67c 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -32,7 +32,7 @@ Mostrar atualizações disponíveis Mostrar uma notificação quando houver atualizações de aplicativos disponíveis Mostrar aplicativos: - Mostrar aplicativos comuns + Mostrar aplicativos Mostrar aplicativos de código aberto Mostrar PWAs Por favor, selecione pelo menos uma fonte de aplicativos. @@ -103,7 +103,7 @@ Aviso de Conteúdo Aplicativos comuns indisponíveis Aplicativos de Código Aberto e PWA indisponíveis - Ocorreu um erro ao carregar aplicativos Comuns. Somente aplicativos de Código Aberto e PWA estão disponíveis no momento. + Ocorreu um erro ao carregar aplicativos. Somente aplicativos de Código Aberto e Web Apps estão disponíveis no momento. Ocorreu um erro ao carregar aplicativos PWA e de Código Aberto. Por enquanto, somente os aplicativos Comuns estão disponíveis. Recomendamos criar uma conta do Google dedicada para o App Lounge e, em seguida, fazer login com ela. Isso oferece o melhor equilíbrio entre privacidade e conveniência. Como alternativa, você pode usar o modo Anônimo. Os aplicativos pagos não podem ser instalados no modo anônimo. Faça login na sua conta do Google para instalar aplicativos pagos. diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index aeb36c182..e0a937028 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -29,7 +29,7 @@ Показать только Open Source приложения PWA и Open Source приложения Open Source - Показать обычные приложения + Показать приложения Показать приложения: Показывать уведомление когда для приложения доступны обновления Показывать доступные обновления @@ -196,7 +196,7 @@ App Lounge будет закрыт на время установки обновления. Пожалуйста, не используйте приложение, пока обновление (загрузка и установка) не будет завершено. Вы сможете получить к нему доступ в течение нескольких минут. Обычные приложения недоступны Приложения с открытым исходным кодом и PWA недоступны - При загрузке обычных приложений произошла ошибка. В настоящее время доступны только приложения с открытым исходным кодом и PWA. + При загрузке приложений произошла ошибка. В настоящее время доступны только приложения с открытым исходным кодом и Web Apps. При загрузке PWA и приложений с открытым исходным кодом произошла ошибка. В настоящее время доступны только обычные приложения. Выберите способ входа diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index 7c05a5754..b2adfc279 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -66,7 +66,7 @@ Takéto aplikácie sa budú aktualizovať z kategórií bežných a open source aplikácií. Zobraziť upozornenie, keď sú dostupné aktualizácie aplikácií Zobraziť aplikácie: - Zobraziť bežné aplikácie + Zobraziť aplikácie Zobraziť open source aplikácie Zobraziť PWA O aplikácii @@ -202,7 +202,7 @@ Stlačte Skúsiť znova. Získava sa hodnotenie obsahu pre všetky nainštalované aplikácie. Bežné aplikácie nie sú dostupné Open Source aplikácie a PWA nie sú dostupné - Pri načítavaní bežných aplikácií došlo k chybe. Zatiaľ sú dostupné iba Open Source aplikácie a PWA. + Pri načítavaní aplikácií došlo k chybe. Zatiaľ sú dostupné iba Open Source aplikácie a Web Apps. Pri načítavaní PWA a Open Source aplikácií došlo k chybe. Zatiaľ sú dostupné iba bežné aplikácie. Aplikácia nie je dostupná Táto aplikácia nie je dostupná na inštaláciu. Zvyčajne je to spôsobené obsahovými obmedzeniami na základe vašej polohy (regiónu) alebo vekových nastavení účtu (vrátane overenia veku a vekového/obsahového hodnotenia). diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index b48426901..9dfb5cc4c 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -38,7 +38,7 @@ Hämta och installera appuppdateringar i bakgrunden Visa tillgängliga uppdateringar Visa appar: - Visa vanliga appar + Visa appar Om Kopierad Konto @@ -194,7 +194,7 @@ Ett fel uppstod vid inläsning av PWA-appar och appar med öppen källkod. Endast vanliga appar är tillgängliga just nu. Vanliga appar är inte tillgängliga Appar med öppen källkod och PWA-appar är inte tillgängliga - Ett fil uppstod vid inläsning av vanliga appar. Endast appar med öppen källkod och PWA-appar är tillgängliga just nu. + Ett fil uppstod vid inläsning av appar. Endast appar med öppen källkod och Web Apps är tillgängliga just nu. App Lounge kommer stängas under dess uppdatering. Undvik att göra något i App Lounge till dess att uppdateringen (hämtning + installation) är färdig. Du kommer få åtkomst om några minuter. Välj hur du vill logga in diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index c7e2fe98d..c858b3e3f 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -26,7 +26,7 @@ Güncellemeleri otomatik olarak yükle Uygulama güncellemelerini arka planda indirin ve yükleyin Uygulamaları Göster: - Yaygın uygulamaları göster + Uygulamaları göster Açık kaynaklı uygulamaları göster PWA\'ları göster Hakkında @@ -188,7 +188,7 @@ \"%1$s\" seçildiğinde tarayıcınızda uygulamanın paket adı önceden doldurulmuş bir sekme açılır.<br /><br />Exodus tarafından analizi başlatmak için \"Perform analysis\" seçeneğine tıklayın.<br /><br />\"See the report\" düğmesi göründüğünde (uygulamaya bağlı olarak biraz zaman alabilir) sekmeyi kapatıp %2$s içindeki uygulama açıklamasına geri dönebilirsiniz; burada Gizlilik Skoru\'nu görmelisiniz. Bazen Exodus uygulamayı analiz edemeyebilir.<br /><br />Not: skorun uygulama açıklamasında görünmesi 10 dakikaya kadar sürebilir. Ortak uygulamalar kullanılamıyor Açık kaynak uygulamalar ve PWA kullanılamıyor - Ortak uygulamalar yüklenirken bir hata oluştu. Şimdilik yalnızca Açık Kaynak uygulamalar ve PWA kullanılabilir. + Uygulamalar yüklenirken bir hata oluştu. Şimdilik yalnızca Açık Kaynak uygulamalar ve Web Apps kullanılabilir. PWA ve Açık Kaynak uygulamalar yüklenirken bir hata oluştu. Şimdilik yalnızca Ortak uygulamalar kullanılabilir. Uygulama kullanılamıyor Bu uygulama yükleme için kullanılabilir değil. Bu genellikle konumunuza (bölge) veya hesabın yaş ayarlarına (yaş doğrulama ve yaş/içerik derecelendirmesi dahil) dayalı içerik kısıtlamalarından kaynaklanır. diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 1799676f5..74712e25a 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -27,7 +27,7 @@ Про застосунок Показати прогресивні вебзастосунки Показати застосунки з відкритим кодом - Показати поширені застосунки + Показати застосунки Показати застосунки: Автоматично встановлювати оновлення Надсилати сповіщення коли доступні оновлення додатків @@ -206,7 +206,7 @@ Отримання оцінки вмісту для всіх встановлених вами застосунків. Поширені застосунки недоступні Застосунки з відкритим кодом і PWA недоступні - Під час завантаження поширених застосунків сталася помилка. Наразі доступні лише застосунки з відкритим кодом і PWA. + Під час завантаження застосунків сталася помилка. Наразі доступні лише застосунки з відкритим кодом і Web Apps. Під час завантаження PWA та застосунків з відкритим кодом сталася помилка. Наразі доступні лише поширені застосунки. Застосунок недоступний Цей застосунок недоступний для встановлення. Зазвичай це пов\'язано з обмеженнями вмісту залежно від вашого місцезнаходження (регіону) або вікових налаштувань облікового запису (включно з перевіркою віку та віковим/контентним рейтингом). diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5cf37d4f4..801e2ceb4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -85,7 +85,7 @@ Show available updates Show a notification when app updates are available Show applications: - Show common apps + Show Apps Show open source apps Show PWAs About @@ -251,7 +251,7 @@ Common apps unavailable Open Source apps and PWA unavailable - An error occurred while loading Common apps. Only Open Source apps and PWA are available for now. + An error occurred while loading Apps. Only Open Source and Web apps are available for now. An error occurred while loading PWA and Open Source apps. Only Common apps are available for now. diff --git a/app/src/main/res/xml/settings_preferences.xml b/app/src/main/res/xml/settings_preferences.xml index be838f899..d368da48e 100644 --- a/app/src/main/res/xml/settings_preferences.xml +++ b/app/src/main/res/xml/settings_preferences.xml @@ -96,7 +96,7 @@ -- GitLab From 71fc08795ad7dec978f2e742f5c0979760a9c057 Mon Sep 17 00:00:00 2001 From: Nishith Khanna Date: Tue, 24 Feb 2026 21:44:21 +0530 Subject: [PATCH 18/22] Have cancel button in queued state have accent outline as well --- .../apps/ui/compose/state/InstallButtonStateMapper.kt | 2 +- .../ui/compose/state/InstallButtonStateMapperTest.kt | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt b/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt index cc407f11d..c0df9ac36 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt @@ -223,7 +223,7 @@ private fun buildDefaultBlockedLabel(app: Application): ButtonLabel { private fun buildStyleFor(status: Status, enabled: Boolean): InstallButtonStyle { return when { - status == Status.QUEUED || status == Status.AWAITING -> InstallButtonStyle.Disabled + status == Status.QUEUED -> InstallButtonStyle.Disabled status == Status.INSTALLED || status == Status.UPDATABLE -> { if (enabled) InstallButtonStyle.AccentFill else InstallButtonStyle.Disabled } diff --git a/app/src/test/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapperTest.kt b/app/src/test/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapperTest.kt index 59c242ede..7e70eaf0b 100644 --- a/app/src/test/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapperTest.kt +++ b/app/src/test/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapperTest.kt @@ -215,16 +215,6 @@ class InstallButtonStateMapperTest { assertTrue(state.enabled) } - @Test - fun awaiting_maps_to_disabled_style() { - val state = mapAppToInstallState( - input = defaultInput(app = baseApp(Status.AWAITING)), - ) - assertEquals(R.string.cancel, state.label.resId) - assertEquals(InstallButtonStyle.Disabled, state.style) - assertTrue(state.enabled) - } - @Test fun downloading_progress_below_zero_uses_cancel_label() { val state = mapAppToInstallState( -- GitLab From f8abfc17e619894344a1e3a66787e8c9567f400a Mon Sep 17 00:00:00 2001 From: Nishith Khanna Date: Tue, 24 Feb 2026 16:43:33 +0530 Subject: [PATCH 19/22] Make button color and states consistent in xml and compose --- .../apps/ui/application/ApplicationFragment.kt | 18 +++++++++--------- .../ApplicationListRVAdapter.kt | 3 ++- .../compose/components/SearchResultListItem.kt | 2 +- .../compose/state/InstallButtonStateMapper.kt | 2 +- .../e/apps/utils/MaterialButtonUtils.kt | 12 ++++++------ 5 files changed, 19 insertions(+), 18 deletions(-) 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 f551b6af9..2b2877f51 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 @@ -20,7 +20,6 @@ package foundation.e.apps.ui.application import android.annotation.SuppressLint import android.content.Intent -import android.graphics.Color import android.graphics.drawable.Drawable import android.os.Bundle import android.text.Html @@ -85,6 +84,7 @@ import kotlinx.coroutines.withContext import timber.log.Timber import java.util.Locale import javax.inject.Inject +import foundation.e.elib.R as eR @AndroidEntryPoint class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { @@ -868,8 +868,8 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { private fun MaterialButton.disableInstallButton(buttonStringID: Int) { isEnabled = false text = context.getString(buttonStringID) - strokeColor = ContextCompat.getColorStateList(context, R.color.light_grey) - setTextColor(context.getColor(R.color.light_grey)) + strokeColor = ContextCompat.getColorStateList(context, eR.color.e_disabled_color) + setTextColor(context.getColor(eR.color.e_disabled_color)) backgroundTintList = ContextCompat.getColorStateList(context, android.R.color.transparent) } @@ -877,8 +877,8 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { private fun MaterialButton.enableInstallButton(buttonStringID: Int) { isEnabled = true text = context.getString(buttonStringID) - strokeColor = ContextCompat.getColorStateList(context, R.color.colorAccent) - setTextColor(context.getColor(R.color.colorAccent)) + strokeColor = ContextCompat.getColorStateList(context, eR.color.e_accent) + setTextColor(context.getColor(eR.color.e_accent)) backgroundTintList = ContextCompat.getColorStateList(context, android.R.color.transparent) } @@ -914,9 +914,9 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { } else { getString(R.string.update) } - setTextColor(Color.WHITE) + setTextColor(ContextCompat.getColor(view.context, eR.color.e_background)) backgroundTintList = - ContextCompat.getColorStateList(view.context, R.color.colorAccent) + ContextCompat.getColorStateList(view.context, eR.color.e_accent) setOnClickListener { if (mainActivityViewModel.checkUnsupportedApplication(application, activity)) { return@setOnClickListener @@ -941,9 +941,9 @@ class ApplicationFragment : TimeoutFragment(R.layout.fragment_application) { appSize.visibility = View.VISIBLE installButton.apply { enableInstallButton(R.string.open) - setTextColor(Color.WHITE) + setTextColor(ContextCompat.getColor(view.context, eR.color.e_background)) backgroundTintList = - ContextCompat.getColorStateList(view.context, R.color.colorAccent) + ContextCompat.getColorStateList(view.context, eR.color.e_accent) setOnClickListener { if (application.is_pwa) { pwaManager.launchPwa(application) 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 812071cd0..bc02389f7 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 @@ -58,6 +58,7 @@ import foundation.e.apps.utils.disableInstallButton import foundation.e.apps.utils.enableInstallButton import timber.log.Timber import javax.inject.Singleton +import foundation.e.elib.R as eR @Singleton class ApplicationListRVAdapter( private val applicationInstaller: ApplicationInstaller, @@ -433,7 +434,7 @@ class ApplicationListRVAdapter( materialButton.enableInstallButton() materialButton.text = materialButton.context.getString(R.string.install) materialButton.strokeColor = - ContextCompat.getColorStateList(holder.itemView.context, R.color.light_grey) + ContextCompat.getColorStateList(holder.itemView.context, eR.color.e_disabled_color) applicationListItemBinding.progressBarInstall.visibility = View.GONE } else -> { diff --git a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt index 37f678dec..618ccc878 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/components/SearchResultListItem.kt @@ -200,7 +200,7 @@ private fun PrimaryActionArea( ) { val accentColor = MaterialTheme.colorScheme.tertiary val labelTextColor = when { - uiState.isFilledStyle -> Color.White + uiState.isFilledStyle -> colorResource(eR.color.e_background) uiState.isDisabledStyle -> colorResource(eR.color.e_disabled_color) else -> accentColor } diff --git a/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt b/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt index c0df9ac36..4152b2000 100644 --- a/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt +++ b/app/src/main/java/foundation/e/apps/ui/compose/state/InstallButtonStateMapper.kt @@ -223,7 +223,7 @@ private fun buildDefaultBlockedLabel(app: Application): ButtonLabel { private fun buildStyleFor(status: Status, enabled: Boolean): InstallButtonStyle { return when { - status == Status.QUEUED -> InstallButtonStyle.Disabled + status == Status.QUEUED || status == Status.INSTALLING -> InstallButtonStyle.Disabled status == Status.INSTALLED || status == Status.UPDATABLE -> { if (enabled) InstallButtonStyle.AccentFill else InstallButtonStyle.Disabled } diff --git a/app/src/main/java/foundation/e/apps/utils/MaterialButtonUtils.kt b/app/src/main/java/foundation/e/apps/utils/MaterialButtonUtils.kt index cde1c27a8..45a1ec1e1 100644 --- a/app/src/main/java/foundation/e/apps/utils/MaterialButtonUtils.kt +++ b/app/src/main/java/foundation/e/apps/utils/MaterialButtonUtils.kt @@ -17,11 +17,11 @@ package foundation.e.apps.utils -import android.graphics.Color import androidx.core.content.ContextCompat import com.google.android.material.button.MaterialButton import foundation.e.apps.R import foundation.e.apps.data.enums.Status +import foundation.e.elib.R as eR fun MaterialButton.disableInstallButton(status: Status? = null) { toggleEnableMaterialButton(false, status) @@ -49,16 +49,16 @@ private fun MaterialButton.getBackgroundTintList(status: Status?) = private fun MaterialButton.getStrokeColor( isEnabled: Boolean, ) = if (isEnabled) { - ContextCompat.getColorStateList(this.context, R.color.colorAccent) + ContextCompat.getColorStateList(this.context, eR.color.e_accent) } else { - ContextCompat.getColorStateList(this.context, R.color.light_grey) + ContextCompat.getColorStateList(this.context, eR.color.e_disabled_color) } private fun MaterialButton.setButtonTextColor(isEnabled: Boolean, status: Status?) = if (isEnabled && (status == Status.INSTALLED || status == Status.UPDATABLE)) { - setTextColor(Color.WHITE) + setTextColor(context.getColor(eR.color.e_background)) } else if (isEnabled) { - setTextColor(context.getColor(R.color.colorAccent)) + setTextColor(context.getColor(eR.color.e_accent)) } else { - setTextColor(context.getColor(R.color.light_grey)) + setTextColor(context.getColor(eR.color.e_disabled_color)) } -- GitLab From a241eedc3d01e8b7015deca367bc1417939c0021 Mon Sep 17 00:00:00 2001 From: Nishith Khanna Date: Tue, 24 Feb 2026 17:33:41 +0530 Subject: [PATCH 20/22] Fix toolbar buttons and make it follow our current palette --- .../e/apps/ui/applicationlist/ApplicationListRVAdapter.kt | 2 +- app/src/main/res/drawable/ic_arrow_back.xml | 2 +- app/src/main/res/layout/fragment_application.xml | 2 +- app/src/main/res/values/themes.xml | 5 +++-- 4 files changed, 6 insertions(+), 5 deletions(-) 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 bc02389f7..4d02f72e8 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 @@ -434,7 +434,7 @@ class ApplicationListRVAdapter( materialButton.enableInstallButton() materialButton.text = materialButton.context.getString(R.string.install) materialButton.strokeColor = - ContextCompat.getColorStateList(holder.itemView.context, eR.color.e_disabled_color) + ContextCompat.getColorStateList(holder.itemView.context, eR.color.e_accent) applicationListItemBinding.progressBarInstall.visibility = View.GONE } else -> { diff --git a/app/src/main/res/drawable/ic_arrow_back.xml b/app/src/main/res/drawable/ic_arrow_back.xml index 2a31b2ef3..ddc3a3147 100644 --- a/app/src/main/res/drawable/ic_arrow_back.xml +++ b/app/src/main/res/drawable/ic_arrow_back.xml @@ -3,7 +3,7 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24" - android:tint="?attr/colorControlNormal" + android:tint="@color/e_primary_text_color" android:autoMirrored="true"> diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index c25cfc64e..2c8baa0e9 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -52,8 +52,9 @@