diff --git a/WordPress/src/main/java/org/wordpress/android/ui/bloggingprompts/promptslist/compose/BloggingPromptsListScreen.kt b/WordPress/src/main/java/org/wordpress/android/ui/bloggingprompts/promptslist/compose/BloggingPromptsListScreen.kt index e499fad2f4b2..a809a3bdc48c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/bloggingprompts/promptslist/compose/BloggingPromptsListScreen.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/bloggingprompts/promptslist/compose/BloggingPromptsListScreen.kt @@ -112,8 +112,8 @@ private fun FetchErrorContent() { @Composable private fun NetworkErrorContent() { EmptyContent( - title = stringResource(R.string.blogging_prompts_list_error_network_title), - subtitle = stringResource(R.string.blogging_prompts_list_error_network_subtitle), + title = stringResource(R.string.no_connection_error_title), + subtitle = stringResource(R.string.no_connection_error_description), image = R.drawable.img_illustration_cloud_off_152dp, modifier = Modifier.fillMaxSize(), ) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderTagsFeedFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderTagsFeedFragment.kt index b96d71fef96b..531c9742fc38 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderTagsFeedFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderTagsFeedFragment.kt @@ -101,6 +101,7 @@ class ReaderTagsFeedFragment : ViewPagerFragment(R.layout.reader_tag_feed_fragme observeErrorMessageEvents() observeSnackbarEvents() observeOpenMoreMenuEvents() + viewModel.onViewCreated() } override fun onDestroy() { @@ -282,8 +283,8 @@ class ReaderTagsFeedFragment : ViewPagerFragment(R.layout.reader_tag_feed_fragme private fun observeErrorMessageEvents() { viewModel.errorMessageEvents.observeEvent(viewLifecycleOwner) { stringRes -> - activity?.findViewById(android.R.id.content)?.let { view -> - WPSnackbar.make(view, getString(stringRes), Snackbar.LENGTH_LONG).show() + if (isAdded) { + WPSnackbar.make(binding.root, getString(stringRes), Snackbar.LENGTH_LONG).show() } } } @@ -291,20 +292,18 @@ class ReaderTagsFeedFragment : ViewPagerFragment(R.layout.reader_tag_feed_fragme private fun observeSnackbarEvents() { viewModel.snackbarEvents.observeEvent(viewLifecycleOwner) { snackbarMessageHolder -> if (isAdded) { - activity?.findViewById(R.id.coordinator)?.let { coordinator -> - with(snackbarMessageHolder) { - val snackbar = WPSnackbar.make( - coordinator, - uiHelpers.getTextOfUiString(requireContext(), message), - Snackbar.LENGTH_LONG - ) - if (buttonTitle != null) { - snackbar.setAction(uiHelpers.getTextOfUiString(requireContext(), buttonTitle)) { - buttonAction.invoke() - } + with(snackbarMessageHolder) { + val snackbar = WPSnackbar.make( + binding.root, + uiHelpers.getTextOfUiString(requireContext(), message), + Snackbar.LENGTH_LONG + ) + if (buttonTitle != null) { + snackbar.setAction(uiHelpers.getTextOfUiString(requireContext(), buttonTitle)) { + buttonAction.invoke() } - snackbar.show() } + snackbar.show() } } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/viewmodels/tagsfeed/ReaderTagsFeedViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/viewmodels/tagsfeed/ReaderTagsFeedViewModel.kt index 30a21829e1bf..2a0344f7ef56 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/viewmodels/tagsfeed/ReaderTagsFeedViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/viewmodels/tagsfeed/ReaderTagsFeedViewModel.kt @@ -6,6 +6,7 @@ import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.update @@ -32,6 +33,7 @@ import org.wordpress.android.ui.reader.repository.usecases.PostLikeUseCase import org.wordpress.android.ui.reader.tracker.ReaderTracker import org.wordpress.android.ui.reader.views.compose.tagsfeed.TagsFeedPostItem import org.wordpress.android.util.DisplayUtilsWrapper +import org.wordpress.android.util.NetworkUtilsWrapper import org.wordpress.android.viewmodel.Event import org.wordpress.android.viewmodel.ScopedViewModel import org.wordpress.android.viewmodel.SingleLiveEvent @@ -50,6 +52,7 @@ class ReaderTagsFeedViewModel @Inject constructor( private val readerPostUiStateBuilder: ReaderPostUiStateBuilder, private val displayUtilsWrapper: DisplayUtilsWrapper, private val readerTracker: ReaderTracker, + private val networkUtilsWrapper: NetworkUtilsWrapper, ) : ScopedViewModel(bgDispatcher) { private val _uiStateFlow: MutableStateFlow = MutableStateFlow(UiState.Initial) val uiStateFlow: StateFlow = _uiStateFlow @@ -75,6 +78,16 @@ class ReaderTagsFeedViewModel @Inject constructor( private var hasInitialized = false + fun onViewCreated() { + if (!hasInitialized) { + hasInitialized = true + readerPostCardActionsHandler.initScope(viewModelScope) + initNavigationEvents() + initSnackbarEvents() + initUiState() + } + } + /** * Fetch multiple tag posts in parallel. Each tag load causes a new state to be emitted, so multiple emissions of * [uiStateFlow] are expected when calling this method for each tag, since each can go through the following @@ -93,13 +106,6 @@ class ReaderTagsFeedViewModel @Inject constructor( return } - if (!hasInitialized) { - hasInitialized = true - readerPostCardActionsHandler.initScope(viewModelScope) - initNavigationEvents() - initSnackbarEvents() - } - // Add tags to the list with the posts loading UI _uiStateFlow.update { readerTagsFeedUiStateMapper.mapInitialPostsUiState( @@ -125,6 +131,27 @@ class ReaderTagsFeedViewModel @Inject constructor( } } + private fun initUiState() { + _uiStateFlow.value = if (networkUtilsWrapper.isNetworkAvailable()) { + UiState.Loading + } else { + UiState.NoConnection(::onNoConnectionRetryClick) + } + } + + private fun onNoConnectionRetryClick() { + _uiStateFlow.value = UiState.Loading + if (networkUtilsWrapper.isNetworkAvailable()) { + _actionEvents.value = ActionEvent.RefreshTags + } else { + // delay a bit before returning to NoConnection for a better feedback to the user + launch { + delay(NO_CONNECTION_DELAY) + _uiStateFlow.value = UiState.NoConnection(::onNoConnectionRetryClick) + } + } + } + /** * Fetch posts for a single tag. This method will emit a new state to [uiStateFlow] for different [UiState]s: * [UiState.Initial], [UiState.Loaded], [UiState.Loading], [UiState.Empty], but only for the tag being fetched. @@ -210,6 +237,11 @@ class ReaderTagsFeedViewModel @Inject constructor( @VisibleForTesting fun onRefresh() { + if (!networkUtilsWrapper.isNetworkAvailable()) { + _errorMessageEvents.postValue(Event(R.string.no_network_message)) + return + } + _uiStateFlow.update { (it as? UiState.Loaded)?.copy(isRefreshing = true) ?: it } @@ -217,6 +249,8 @@ class ReaderTagsFeedViewModel @Inject constructor( } fun onBackFromTagDetails() { + if (!networkUtilsWrapper.isNetworkAvailable()) return + _actionEvents.value = ActionEvent.RefreshTags } @@ -501,6 +535,8 @@ class ReaderTagsFeedViewModel @Inject constructor( data object Loading : UiState() data class Empty(val onOpenTagsListClick: () -> Unit) : UiState() + + data class NoConnection(val onRetryClick: () -> Unit) : UiState() } data class TagFeedItem( @@ -542,4 +578,8 @@ class ReaderTagsFeedViewModel @Inject constructor( val readerCardUiState: ReaderCardUiState.ReaderPostNewUiState, val readerPostCardActions: List, ) + + companion object { + private const val NO_CONNECTION_DELAY = 500L + } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/views/compose/tagsfeed/ReaderTagsFeed.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/views/compose/tagsfeed/ReaderTagsFeed.kt index ef85b60a357c..789bf55173d7 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/views/compose/tagsfeed/ReaderTagsFeed.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/views/compose/tagsfeed/ReaderTagsFeed.kt @@ -21,6 +21,7 @@ import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Button import androidx.compose.material.ButtonDefaults @@ -78,6 +79,7 @@ fun ReaderTagsFeed(uiState: UiState) { is UiState.Loading -> Loading() is UiState.Loaded -> Loaded(uiState) is UiState.Empty -> Empty(uiState) + is UiState.NoConnection -> NoConnection(uiState) is UiState.Initial -> { // no-op } @@ -134,7 +136,7 @@ private fun Loaded(uiState: UiState.Loaded) { when (postList) { is PostList.Initial, is PostList.Loading -> PostListLoading() is PostList.Loaded -> PostListLoaded(postList, tagChip, backgroundColor) - is PostList.Error -> PostListError(backgroundColor, tagChip, postList) + is PostList.Error -> PostListError(postList, tagChip, backgroundColor) } Spacer(modifier = Modifier.height(Margin.ExtraExtraMediumLarge.value)) } @@ -266,6 +268,28 @@ private fun Empty(uiState: UiState.Empty) { } } +@Composable +fun NoConnection(uiState: UiState.NoConnection) { + val backgroundColor = if (isSystemInDarkTheme()) { + AppColor.White.copy(alpha = 0.12F) + } else { + AppColor.Black.copy(alpha = 0.08F) + } + + Box(modifier = Modifier.fillMaxSize()) { + ErrorMessage( + modifier = Modifier + .align(Alignment.Center) + .fillMaxWidth(), + backgroundColor = backgroundColor, + titleText = stringResource(R.string.no_connection_error_title), + descriptionText = stringResource(R.string.no_connection_error_description), + actionText = stringResource(R.string.reader_tags_feed_error_retry), + onActionClick = uiState.onRetryClick, + ) + } +} + @Composable private fun PostListLoading() { val loadingLabel = stringResource(id = R.string.loading) @@ -369,47 +393,65 @@ private fun PostListLoaded( @Composable private fun PostListError( - backgroundColor: Color, - tagChip: TagChip, postList: PostList.Error, + tagChip: TagChip, + backgroundColor: Color, ) { - Column( + val tagName = tagChip.tag.tagDisplayName + val errorMessage = when (postList.type) { + is ErrorType.Default -> stringResource(R.string.reader_tags_feed_loading_error_description) + is ErrorType.NoContent -> stringResource(R.string.reader_tags_feed_no_content_error_description, tagName) + } + + ErrorMessage( modifier = Modifier .heightIn(min = ReaderTagsFeedComposeUtils.PostItemHeight) - .fillMaxWidth() + .fillMaxWidth(), + backgroundColor = backgroundColor, + titleText = stringResource(id = R.string.reader_tags_feed_error_title, tagName), + descriptionText = errorMessage, + actionText = stringResource(R.string.reader_tags_feed_error_retry), + onActionClick = { postList.onRetryClick(tagChip.tag) } + ) +} + +@Composable +private fun ErrorMessage( + backgroundColor: Color, + titleText: String, + descriptionText: String, + actionText: String, + modifier: Modifier = Modifier, + onActionClick: () -> Unit, +) { + Column( + modifier = modifier .semantics(mergeDescendants = true) {} .padding(start = 60.dp, end = 60.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, ) { - Spacer(modifier = Modifier.height(Margin.Medium.value)) Icon( modifier = Modifier - .drawBehind { - drawCircle( - color = backgroundColor, - radius = this.size.maxDimension - ) - }, + .background( + color = backgroundColor, + shape = CircleShape + ) + .padding(Margin.Medium.value), painter = painterResource(R.drawable.ic_wifi_off_24px), tint = MaterialTheme.colors.onSurface, contentDescription = null ) Spacer(modifier = Modifier.height(Margin.ExtraMediumLarge.value)) - val tagName = tagChip.tag.tagDisplayName Text( - text = stringResource(id = R.string.reader_tags_feed_error_title, tagName), + text = titleText, style = androidx.compose.material3.MaterialTheme.typography.labelLarge, color = MaterialTheme.colors.onSurface, textAlign = TextAlign.Center, ) Spacer(modifier = Modifier.height(Margin.Small.value)) - val errorMessage = when (postList.type) { - is ErrorType.Default -> stringResource(R.string.reader_tags_feed_loading_error_description) - is ErrorType.NoContent -> stringResource(R.string.reader_tags_feed_no_content_error_description, tagName) - } Text( - text = errorMessage, + text = descriptionText, style = androidx.compose.material3.MaterialTheme.typography.bodySmall, color = if (isSystemInDarkTheme()) { AppColor.White.copy(alpha = 0.4F) @@ -420,7 +462,7 @@ private fun PostListError( ) Spacer(modifier = Modifier.height(Margin.Large.value)) Button( - onClick = { postList.onRetryClick(tagChip.tag) }, + onClick = onActionClick, modifier = Modifier .height(36.dp) .widthIn(min = 114.dp), @@ -440,7 +482,7 @@ private fun PostListError( style = androidx.compose.material3.MaterialTheme.typography.labelLarge, fontWeight = FontWeight.Medium, color = MaterialTheme.colors.surface, - text = stringResource(R.string.reader_tags_feed_error_retry), + text = actionText, ) } } diff --git a/WordPress/src/main/res/values-ar/strings.xml b/WordPress/src/main/res/values-ar/strings.xml index 8a48702ee148..4afff1755719 100644 --- a/WordPress/src/main/res/values-ar/strings.xml +++ b/WordPress/src/main/res/values-ar/strings.xml @@ -534,14 +534,14 @@ Language: ar ستنتقل ميزة التنبيهات إلى Jetpack ستنتقل ميزة القارئ إلى تطبيق Jetpack التبديل إلى تطبيق Jetpack الجديد - يتعذر تحميل هذا المحتوى حاليًا. + يتعذر تحميل هذا المحتوى حاليًا. حدث خطأ في أثناء تحميل المطالبات. عذرًا لا توجد مطالبات بعد %d من الإجابات إجابة واحدة ستنتقل ميزة الإحصاءات لديك إلى تطبيق Jetpack - تحقق من اتصالك بالشبكة وحاول مرة أخرى. + تحقق من اتصالك بالشبكة وحاول مرة أخرى. 0 من الإجابات ✓ تم الرد المطالبات diff --git a/WordPress/src/main/res/values-cs/strings.xml b/WordPress/src/main/res/values-cs/strings.xml index a7e128c3e6cb..d8b4b56bf66b 100644 --- a/WordPress/src/main/res/values-cs/strings.xml +++ b/WordPress/src/main/res/values-cs/strings.xml @@ -148,8 +148,8 @@ Language: cs_CZ Čtečka se přesouvá do aplikace Jetpack Vaše statistiky se přesouvají do aplikace Jetpack Přepněte na novou aplikaci Jetpack - Zkontrolujte připojení k síti a zkuste to znovu. - Momentálně tento obsah nelze načíst + Zkontrolujte připojení k síti a zkuste to znovu. + Momentálně tento obsah nelze načíst Došlo k chybě při načítání to se mi líbí Jejda Zatím žádné výzvy diff --git a/WordPress/src/main/res/values-de/strings.xml b/WordPress/src/main/res/values-de/strings.xml index 995411887988..5f2d7106d702 100644 --- a/WordPress/src/main/res/values-de/strings.xml +++ b/WordPress/src/main/res/values-de/strings.xml @@ -549,8 +549,8 @@ Language: de Der Reader wird in die Jetpack-App verschoben Deine Statistiken werden in die Jetpack-App verschoben Zur neuen Jetpack-App wechseln - Prüfe deine Netzwerkverbindung und versuche es erneut. - Dieser Inhalt kann gerade nicht geladen werden + Prüfe deine Netzwerkverbindung und versuche es erneut. + Dieser Inhalt kann gerade nicht geladen werden Beim Laden der Schreibanregungen ist ein Fehler aufgetreten. Ups Noch keine Schreibanregungen diff --git a/WordPress/src/main/res/values-en-rCA/strings.xml b/WordPress/src/main/res/values-en-rCA/strings.xml index bf42b4a96689..44e41f34c9d7 100644 --- a/WordPress/src/main/res/values-en-rCA/strings.xml +++ b/WordPress/src/main/res/values-en-rCA/strings.xml @@ -491,8 +491,8 @@ Language: en_CA Stats, Reader, Notifications and other features will soon move to the Jetpack mobile app. There was an error loading prompts. Oops - Check your network connection and try again. - Unable to load this content right now + Check your network connection and try again. + Unable to load this content right now No prompts yet 1 answer %d answers diff --git a/WordPress/src/main/res/values-en-rGB/strings.xml b/WordPress/src/main/res/values-en-rGB/strings.xml index 7f5704278c21..1e5b512815c1 100644 --- a/WordPress/src/main/res/values-en-rGB/strings.xml +++ b/WordPress/src/main/res/values-en-rGB/strings.xml @@ -549,8 +549,8 @@ Language: en_GB Reader is moving to the Jetpack app Your stats are moving to the Jetpack app Switch to the new Jetpack app - Check your network connection and try again. - Unable to load this content right now + Check your network connection and try again. + Unable to load this content right now There was an error loading prompts. Oops No prompts yet diff --git a/WordPress/src/main/res/values-es-rCO/strings.xml b/WordPress/src/main/res/values-es-rCO/strings.xml index a09dd4e8652c..eac1fde19f77 100644 --- a/WordPress/src/main/res/values-es-rCO/strings.xml +++ b/WordPress/src/main/res/values-es-rCO/strings.xml @@ -549,8 +549,8 @@ Language: es_CO El lector se está trasladando a la aplicación de Jetpack La estadísticas se están trasladado a la aplicación de Jetpack Cambiar a la nueva aplicación de Jetpack - Comprueba tu conexión a la red e inténtalo de nuevo. - En este momento no se ha podido cargar este contenido + Comprueba tu conexión a la red e inténtalo de nuevo. + En este momento no se ha podido cargar este contenido Se ha producido un error al cargar las indicaciones. ¡Vaya! Todavía no hay sugerencias diff --git a/WordPress/src/main/res/values-es/strings.xml b/WordPress/src/main/res/values-es/strings.xml index d44702d9f362..3041cd1330c5 100644 --- a/WordPress/src/main/res/values-es/strings.xml +++ b/WordPress/src/main/res/values-es/strings.xml @@ -549,8 +549,8 @@ Language: es El lector se está trasladando a la aplicación de Jetpack La estadísticas se están trasladado a la aplicación de Jetpack Cambiar a la nueva aplicación de Jetpack - Comprueba tu conexión a la red e inténtalo de nuevo. - En este momento no se ha podido cargar este contenido + Comprueba tu conexión a la red e inténtalo de nuevo. + En este momento no se ha podido cargar este contenido Se ha producido un error al cargar las indicaciones. ¡Vaya! Todavía no hay sugerencias diff --git a/WordPress/src/main/res/values-fr-rCA/strings.xml b/WordPress/src/main/res/values-fr-rCA/strings.xml index bb762e3bd384..99007a63887d 100644 --- a/WordPress/src/main/res/values-fr-rCA/strings.xml +++ b/WordPress/src/main/res/values-fr-rCA/strings.xml @@ -542,8 +542,8 @@ Language: fr Le lecteur va être déplacé dans l’application Jetpack Les statistiques vont être déplacées dans l’application Jetpack Passer à la nouvelle application Jetpack - Vérifiez votre connexion réseau et réessayez. - Impossible de charger ce contenu pour le moment + Vérifiez votre connexion réseau et réessayez. + Impossible de charger ce contenu pour le moment Un problème est survenu lors du chargement des incitations. Oups Pas encore d’incitation diff --git a/WordPress/src/main/res/values-fr/strings.xml b/WordPress/src/main/res/values-fr/strings.xml index bb762e3bd384..99007a63887d 100644 --- a/WordPress/src/main/res/values-fr/strings.xml +++ b/WordPress/src/main/res/values-fr/strings.xml @@ -542,8 +542,8 @@ Language: fr Le lecteur va être déplacé dans l’application Jetpack Les statistiques vont être déplacées dans l’application Jetpack Passer à la nouvelle application Jetpack - Vérifiez votre connexion réseau et réessayez. - Impossible de charger ce contenu pour le moment + Vérifiez votre connexion réseau et réessayez. + Impossible de charger ce contenu pour le moment Un problème est survenu lors du chargement des incitations. Oups Pas encore d’incitation diff --git a/WordPress/src/main/res/values-gl/strings.xml b/WordPress/src/main/res/values-gl/strings.xml index b4d23cc2778e..5006494cabc3 100644 --- a/WordPress/src/main/res/values-gl/strings.xml +++ b/WordPress/src/main/res/values-gl/strings.xml @@ -556,9 +556,9 @@ Language: gl_ES Os avisos estanse trasladando á aplicación de Jetpack O lector estase trasladando á aplicación de Jetpack Produciuse un erro ao cargar as indicacións. - Neste momento non se puido cargar este contido + Neste momento non se puido cargar este contido A estatísticas estanse trasladado á aplicación de Jetpack - Comproba a túa conexión á rede e inténtao de novo. + Comproba a túa conexión á rede e inténtao de novo. Peticións ✓ Respondido pechar diff --git a/WordPress/src/main/res/values-he/strings.xml b/WordPress/src/main/res/values-he/strings.xml index 212e233c0619..9a13d85610f7 100644 --- a/WordPress/src/main/res/values-he/strings.xml +++ b/WordPress/src/main/res/values-he/strings.xml @@ -542,8 +542,8 @@ Language: he_IL הכלי Reader עובר לאפליקציה של Jetpack הנתונים הסטטיסטיים שלך עוברים לאפליקציה של Jetpack לעבור לאפליקציה החדשה של Jetpack - יש לבדוק את החיבור לרשת ולנסות שוב. - אין אפשרות לטעון את התוכן כרגע + יש לבדוק את החיבור לרשת ולנסות שוב. + אין אפשרות לטעון את התוכן כרגע אירעה שגיאה בטעינת ההצעות. אופס עדיין אין הצעות diff --git a/WordPress/src/main/res/values-id/strings.xml b/WordPress/src/main/res/values-id/strings.xml index d5fff60fe9fe..8233297376fd 100644 --- a/WordPress/src/main/res/values-id/strings.xml +++ b/WordPress/src/main/res/values-id/strings.xml @@ -548,8 +548,8 @@ Language: id Reader akan berpindah ke aplikasi Jetpack Statistik Anda akan berpindah ke aplikasi Jetpack Beralih ke aplikasi Jetpack baru - Periksa koneksi internet Anda dan coba lagi. - Tidak dapat memuat konten ini sekarang + Periksa koneksi internet Anda dan coba lagi. + Tidak dapat memuat konten ini sekarang Terjadi eror saat memuat prompt. Waduh Belum ada prompt diff --git a/WordPress/src/main/res/values-it/strings.xml b/WordPress/src/main/res/values-it/strings.xml index 86385c8715c0..b1c509251ad5 100644 --- a/WordPress/src/main/res/values-it/strings.xml +++ b/WordPress/src/main/res/values-it/strings.xml @@ -543,8 +543,8 @@ Language: it Le notifiche si stanno spostando sull\'app Jetpack Le tue statistiche si stanno spostando sull\'app Jetpack Passa alla nuova app Jetpack - Controlla la connessione di rete e riprova. - Impossibile caricare questo contenuto al momento + Controlla la connessione di rete e riprova. + Impossibile caricare questo contenuto al momento Si è verificato un errore durante il caricamento delle richieste. Ops Ancora nessuna richiesta diff --git a/WordPress/src/main/res/values-ja/strings.xml b/WordPress/src/main/res/values-ja/strings.xml index e0d1f587b197..443a856f6581 100644 --- a/WordPress/src/main/res/values-ja/strings.xml +++ b/WordPress/src/main/res/values-ja/strings.xml @@ -538,8 +538,8 @@ Language: ja_JP Reader は Jetpack アプリに移動しています 統計は Jetpack アプリに移動しています 新しい Jetpack アプリに切り替える - ネットワーク接続を確認して、もう一度お試しください。 - 現在このページを読み込めません + ネットワーク接続を確認して、もう一度お試しください。 + 現在このページを読み込めません プロンプトの読み込みでエラーが発生しました。 エラーです プロンプトはまだありません diff --git a/WordPress/src/main/res/values-ko/strings.xml b/WordPress/src/main/res/values-ko/strings.xml index 14fe72e23c0d..fa1858c54c0e 100644 --- a/WordPress/src/main/res/values-ko/strings.xml +++ b/WordPress/src/main/res/values-ko/strings.xml @@ -542,8 +542,8 @@ Language: ko_KR 젯팩 앱으로 리더 이동 중 젯팩 앱으로 통계 이동 중 새 젯팩 앱으로 전환 - 네트워크 연결을 확인하고 다시 시도하세요. - 지금 이 콘텐츠를 로드할 수 없습니다. + 네트워크 연결을 확인하고 다시 시도하세요. + 지금 이 콘텐츠를 로드할 수 없습니다. 프롬프트 로드 중 오류가 발생했습니다. 죄송합니다. 아직 프롬프트 없음 diff --git a/WordPress/src/main/res/values-lv/strings.xml b/WordPress/src/main/res/values-lv/strings.xml index 600711a3a7a2..20cccf2ded05 100644 --- a/WordPress/src/main/res/values-lv/strings.xml +++ b/WordPress/src/main/res/values-lv/strings.xml @@ -280,8 +280,8 @@ Language: lv Lasītājs pāriet uz Jetpack lietotni Jūsu statistika tiek pārvietota uz Jetpack lietotni Pārslēdzieties uz jauno Jetpack lietotni - Pārbaudiet tīkla savienojumu un mēģiniet vēlreiz. - Pašlaik nevar ielādēt šo saturu + Pārbaudiet tīkla savienojumu un mēģiniet vēlreiz. + Pašlaik nevar ielādēt šo saturu Ielādējot uzvednes, radās kļūda. Hmm… Vēl nav uzvedņu diff --git a/WordPress/src/main/res/values-nl/strings.xml b/WordPress/src/main/res/values-nl/strings.xml index 3f3e5c65075f..b13e6af15c54 100644 --- a/WordPress/src/main/res/values-nl/strings.xml +++ b/WordPress/src/main/res/values-nl/strings.xml @@ -549,8 +549,8 @@ Language: nl Reader zal naar de Jetpack-app worden verplaatst Je statistieken zullen naar de Jetpack-app worden verplaatst Schakel over naar de nieuwe Jetpack-app - Controleer je netwerkverbinding en probeer het nogmaals. - Deze inhoud kan momenteel niet geladen worden + Controleer je netwerkverbinding en probeer het nogmaals. + Deze inhoud kan momenteel niet geladen worden Er is een fout opgetreden bij het laden van opdrachten. Oeps Er zijn nog geen opdrachten diff --git a/WordPress/src/main/res/values-pt-rBR/strings.xml b/WordPress/src/main/res/values-pt-rBR/strings.xml index e4a4322da026..d276a53dab52 100644 --- a/WordPress/src/main/res/values-pt-rBR/strings.xml +++ b/WordPress/src/main/res/values-pt-rBR/strings.xml @@ -312,8 +312,8 @@ Language: pt_BR O Leitor está migrando para o aplicativo Jetpack Suas estatísticas estão migrando para o aplicativo Jetpack Mudar para o novo aplicativo do Jetpack - Verifique sua conexão de rede e tente novamente. - Não foi possível carregar esse conteúdo no momento + Verifique sua conexão de rede e tente novamente. + Não foi possível carregar esse conteúdo no momento Ocorreu um erro ao carregar as sugestões. Opa Nenhuma sugestão ainda diff --git a/WordPress/src/main/res/values-ro/strings.xml b/WordPress/src/main/res/values-ro/strings.xml index 36b4adb1ff35..b53e1f914ff9 100644 --- a/WordPress/src/main/res/values-ro/strings.xml +++ b/WordPress/src/main/res/values-ro/strings.xml @@ -549,8 +549,8 @@ Language: ro Cititorul a fost mutat în aplicația Jetpack Statisticile se mută în aplicația Jetpack Comută la noua aplicație Jetpack - Verifică conexiunea rețelei și încearcă din nou. - Nu pot să încarc acest conținut chiar acum + Verifică conexiunea rețelei și încearcă din nou. + Nu pot să încarc acest conținut chiar acum A fost o eroare la încărcarea îndemnurilor. Hopa Niciun îndemn încă diff --git a/WordPress/src/main/res/values-ru/strings.xml b/WordPress/src/main/res/values-ru/strings.xml index c93edc6bb2d2..fb236e7a2f07 100644 --- a/WordPress/src/main/res/values-ru/strings.xml +++ b/WordPress/src/main/res/values-ru/strings.xml @@ -547,8 +547,8 @@ Language: ru Чтиво переезжает в приложение Jetpack Статистика переезжает в приложение Jetpack Перейти в новое приложение Jetpack - Проверьте ваше подключение к сети и попробуйте снова. - Сейчас невозможно загрузить это содержимое + Проверьте ваше подключение к сети и попробуйте снова. + Сейчас невозможно загрузить это содержимое При загрузке подсказок возникла ошибка. Ой! Пока нет подсказок diff --git a/WordPress/src/main/res/values-sq/strings.xml b/WordPress/src/main/res/values-sq/strings.xml index 11a3d337c205..18f2adb9e44c 100644 --- a/WordPress/src/main/res/values-sq/strings.xml +++ b/WordPress/src/main/res/values-sq/strings.xml @@ -520,8 +520,8 @@ Language: sq_AL Lexuesi po kalohet te aplikacioni Jetpack Statistikat tuaja po kalojnë te aplikacioni Jetpack Kaloni në aplikacionin e ri Jetpack - Kontrolloni lidhjen tuaj në rrjet dhe riprovoni. - S’arrihet të ngarkohet kjo lëndë këtë çast + Kontrolloni lidhjen tuaj në rrjet dhe riprovoni. + S’arrihet të ngarkohet kjo lëndë këtë çast Pati një gabim në ngarkim cytjesh. Hëm Ende pa cytje diff --git a/WordPress/src/main/res/values-sv/strings.xml b/WordPress/src/main/res/values-sv/strings.xml index df5eade59e7d..a0fb595b94c8 100644 --- a/WordPress/src/main/res/values-sv/strings.xml +++ b/WordPress/src/main/res/values-sv/strings.xml @@ -549,8 +549,8 @@ Language: sv_SE Läsaren flyttar till Jetpack-appen Din statistik flyttas till Jetpack-appen Byt till den nya Jetpack-appen - Kontrollera din nätverksanslutning och försök igen. - Det går inte att ladda detta innehåll just nu + Kontrollera din nätverksanslutning och försök igen. + Det går inte att ladda detta innehåll just nu Det var ett problem att ladda in förslag. Hoppsan Inga förslag än diff --git a/WordPress/src/main/res/values-tr/strings.xml b/WordPress/src/main/res/values-tr/strings.xml index 6bdc41bf6bd1..4eefcfe02e32 100644 --- a/WordPress/src/main/res/values-tr/strings.xml +++ b/WordPress/src/main/res/values-tr/strings.xml @@ -546,8 +546,8 @@ Language: tr Okuyucu, Jetpack uygulamasına taşınıyor İstatistikleriniz Jetpack uygulamasına taşınıyor Yeni Jetpack uygulamasına geçiş yapın - Ağ bağlantınızı denetleyip yeniden deneyin. - Bu içerik şu an yüklenemiyor + Ağ bağlantınızı denetleyip yeniden deneyin. + Bu içerik şu an yüklenemiyor İstemler yüklenirken bir sorun çıktı. Eyvah Henüz bir istem yok diff --git a/WordPress/src/main/res/values-zh-rCN/strings.xml b/WordPress/src/main/res/values-zh-rCN/strings.xml index 3844b72060a9..9cefd4408257 100644 --- a/WordPress/src/main/res/values-zh-rCN/strings.xml +++ b/WordPress/src/main/res/values-zh-rCN/strings.xml @@ -540,8 +540,8 @@ Language: zh_CN 阅读器即将移至 Jetpack 应用 统计信息即将移至 Jetpack 应用 切换到新版 Jetpack 应用 - 请检查您的网络连接,然后重试。 - 现在无法加载此内容 + 请检查您的网络连接,然后重试。 + 现在无法加载此内容 加载提示时出错。 糟糕 尚无提示 diff --git a/WordPress/src/main/res/values-zh-rHK/strings.xml b/WordPress/src/main/res/values-zh-rHK/strings.xml index 7106eb840445..f6cce6eb1afa 100644 --- a/WordPress/src/main/res/values-zh-rHK/strings.xml +++ b/WordPress/src/main/res/values-zh-rHK/strings.xml @@ -542,8 +542,8 @@ Language: zh_TW 「閱讀器」將轉移至 Jetpack 應用程式 你的統計資料將轉移至 Jetpack 應用程式 切換至全新 Jetpack 應用程式 - 請檢查你的網路連線並再試一次。 - 目前無法載入此內容 + 請檢查你的網路連線並再試一次。 + 目前無法載入此內容 載入提示時發生錯誤。 糟糕 尚無提示 diff --git a/WordPress/src/main/res/values-zh-rTW/strings.xml b/WordPress/src/main/res/values-zh-rTW/strings.xml index 7106eb840445..f6cce6eb1afa 100644 --- a/WordPress/src/main/res/values-zh-rTW/strings.xml +++ b/WordPress/src/main/res/values-zh-rTW/strings.xml @@ -542,8 +542,8 @@ Language: zh_TW 「閱讀器」將轉移至 Jetpack 應用程式 你的統計資料將轉移至 Jetpack 應用程式 切換至全新 Jetpack 應用程式 - 請檢查你的網路連線並再試一次。 - 目前無法載入此內容 + 請檢查你的網路連線並再試一次。 + 目前無法載入此內容 載入提示時發生錯誤。 糟糕 尚無提示 diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index e9ec2d338432..f7486889e865 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -122,6 +122,9 @@ <Experimental> + Unable to load this content right now + Check your network connection and try again. + %d selected @@ -4310,8 +4313,6 @@ translators: %s: Select control option value e.g: "Auto, 25%". --> No prompts yet Oops There was an error loading prompts. - Unable to load this content right now - Check your network connection and try again. Content diff --git a/WordPress/src/test/java/org/wordpress/android/ui/reader/viewmodels/ReaderTagsFeedViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/reader/viewmodels/ReaderTagsFeedViewModelTest.kt index 06368089184f..83baaa4a6c28 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/reader/viewmodels/ReaderTagsFeedViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/reader/viewmodels/ReaderTagsFeedViewModelTest.kt @@ -15,10 +15,12 @@ import org.mockito.Mock import org.mockito.Mockito import org.mockito.kotlin.any import org.mockito.kotlin.doSuspendableAnswer +import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.verifyNoInteractions import org.mockito.kotlin.whenever import org.wordpress.android.BaseUnitTest +import org.wordpress.android.R import org.wordpress.android.analytics.AnalyticsTracker import org.wordpress.android.datasets.wrappers.ReaderPostTableWrapper import org.wordpress.android.getOrAwaitValue @@ -41,9 +43,11 @@ import org.wordpress.android.ui.reader.viewmodels.tagsfeed.ReaderTagsFeedViewMod import org.wordpress.android.ui.reader.viewmodels.tagsfeed.ReaderTagsFeedViewModel.ActionEvent import org.wordpress.android.ui.reader.views.compose.tagsfeed.TagsFeedPostItem import org.wordpress.android.util.DisplayUtilsWrapper +import org.wordpress.android.util.NetworkUtilsWrapper import org.wordpress.android.viewmodel.Event import kotlin.test.assertIs +@Suppress("LargeClass") @OptIn(ExperimentalCoroutinesApi::class) class ReaderTagsFeedViewModelTest : BaseUnitTest() { @Mock @@ -79,12 +83,16 @@ class ReaderTagsFeedViewModelTest : BaseUnitTest() { @Mock lateinit var snackbarEvents: MediatorLiveData> + @Mock + lateinit var networkUtilsWrapper: NetworkUtilsWrapper + private lateinit var viewModel: ReaderTagsFeedViewModel private val collectedUiStates: MutableList = mutableListOf() private val actionEvents = mutableListOf() private val readerNavigationEvents = mutableListOf>() + private val errorMessageEvents = mutableListOf>() val tag = ReaderTag( "tag", @@ -107,6 +115,7 @@ class ReaderTagsFeedViewModelTest : BaseUnitTest() { readerPostUiStateBuilder = readerPostUiStateBuilder, displayUtilsWrapper = displayUtilsWrapper, readerTracker = readerTracker, + networkUtilsWrapper = networkUtilsWrapper, ) whenever(readerPostCardActionsHandler.navigationEvents) .thenReturn(navigationEvents) @@ -114,6 +123,7 @@ class ReaderTagsFeedViewModelTest : BaseUnitTest() { .thenReturn(snackbarEvents) observeActionEvents() observeNavigationEvents() + observeErrorMessageEvents() } @Test @@ -386,6 +396,7 @@ class ReaderTagsFeedViewModelTest : BaseUnitTest() { val posts2 = ReaderPostList().apply { add(ReaderPost()) } + whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(true) whenever(readerPostRepository.fetchNewerPostsForTag(tag1)).doSuspendableAnswer { delay(100) posts1 @@ -448,6 +459,7 @@ class ReaderTagsFeedViewModelTest : BaseUnitTest() { val posts2 = ReaderPostList().apply { add(ReaderPost()) } + whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(true) whenever(readerPostRepository.fetchNewerPostsForTag(tag1)).doSuspendableAnswer { delay(100) posts1 @@ -487,6 +499,7 @@ class ReaderTagsFeedViewModelTest : BaseUnitTest() { val posts2 = ReaderPostList().apply { add(ReaderPost()) } + whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(true) whenever(readerPostRepository.fetchNewerPostsForTag(tag1)).doSuspendableAnswer { delay(100) posts1 @@ -514,6 +527,46 @@ class ReaderTagsFeedViewModelTest : BaseUnitTest() { assertThat(action).isEqualTo(ActionEvent.RefreshTags) } + @Suppress("LongMethod") + @Test + fun `given tags fetched and no connection, when refreshing, then show error message`() = testCollectingUiStates { + // Given + val tag1 = ReaderTestUtils.createTag("tag1") + val tag2 = ReaderTestUtils.createTag("tag2") + val posts1 = ReaderPostList().apply { + add(ReaderPost()) + } + val posts2 = ReaderPostList().apply { + add(ReaderPost()) + } + whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(false) + whenever(readerPostRepository.fetchNewerPostsForTag(tag1)).doSuspendableAnswer { + delay(100) + posts1 + } + whenever(readerPostRepository.fetchNewerPostsForTag(tag2)).doSuspendableAnswer { + delay(200) + posts2 + } + mockMapInitialTagFeedItems() + mockMapLoadingTagFeedItems() + mockMapLoadedTagFeedItems() + + // When + viewModel.onTagsChanged(listOf(tag1, tag2)) + advanceUntilIdle() + viewModel.onItemEnteredView(getInitialTagFeedItem(tag1)) + advanceUntilIdle() + viewModel.onItemEnteredView(getInitialTagFeedItem(tag2)) + advanceUntilIdle() + + // Then + viewModel.onRefresh() + + val messageRes = errorMessageEvents.last().peekContent() + assertThat(messageRes).isEqualTo(R.string.no_network_message) + } + @Test fun `Should update UI immediately when like button is tapped`() = testCollectingUiStates { // Given @@ -603,6 +656,8 @@ class ReaderTagsFeedViewModelTest : BaseUnitTest() { @Test fun `Should emit RefreshTags when onBackFromTagDetails is called`() { + whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(true) + // When viewModel.onBackFromTagDetails() @@ -610,6 +665,17 @@ class ReaderTagsFeedViewModelTest : BaseUnitTest() { assertIs(actionEvents.first()) } + @Test + fun `Should not emit RefreshTags when onBackFromTagDetails is called with no connection`() { + whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(false) + + // When + viewModel.onBackFromTagDetails() + + // Then + actionEvents.isEmpty() + } + @Test fun `Should track READER_POST_CARD_TAPPED when onPostCardClick is called`() = testCollectingUiStates { // Given @@ -699,6 +765,80 @@ class ReaderTagsFeedViewModelTest : BaseUnitTest() { ) } + @Test + fun `when calling onViewCreated multiple times, then initialize handler once`() = test { + // When + viewModel.onViewCreated() + viewModel.onViewCreated() + + // Then + verify(readerPostCardActionsHandler, times(1)).initScope(any()) + } + + @Test + fun `given connection on, when onViewCreated, then init UI state with Loading`() = testCollectingUiStates { + // Given + whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(true) + + // When + viewModel.onViewCreated() + + // Then + assertThat(collectedUiStates.last()).isEqualTo(ReaderTagsFeedViewModel.UiState.Loading) + } + + @Test + fun `given connection off, when onViewCreated, then init UI state with NoConnection`() = testCollectingUiStates { + // Given + whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(false) + + // When + viewModel.onViewCreated() + + // Then + assertThat(collectedUiStates.last()).isInstanceOf(ReaderTagsFeedViewModel.UiState.NoConnection::class.java) + } + + @Test + fun `given NoConnectionState and connection off, when onRetryClick, then UI state is NoConnection`() = + testCollectingUiStates { + // Given + whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(false) + viewModel.onViewCreated() + val noConnectionState = collectedUiStates.last() as ReaderTagsFeedViewModel.UiState.NoConnection + + // When + noConnectionState.onRetryClick() + advanceUntilIdle() + + // Then + val lastStates = collectedUiStates.takeLast(2) + assertThat(lastStates[0]).isEqualTo(ReaderTagsFeedViewModel.UiState.Loading) + assertThat(lastStates[1]).isInstanceOf(ReaderTagsFeedViewModel.UiState.NoConnection::class.java) + } + + @Test + fun `given NoConnectionState and connection on, when onRetryClick, then refresh is requested`() = + testCollectingUiStates { + // Given + whenever(networkUtilsWrapper.isNetworkAvailable()) + .thenReturn(false) + .thenReturn(true) + viewModel.onViewCreated() + val noConnectionState = collectedUiStates.last() as ReaderTagsFeedViewModel.UiState.NoConnection + + // When + noConnectionState.onRetryClick() + advanceUntilIdle() + + // Then + val lastState = collectedUiStates.last() + assertThat(lastState).isEqualTo(ReaderTagsFeedViewModel.UiState.Loading) + viewModel.actionEvents.getOrAwaitValue().let { + assertThat(it).isEqualTo(ActionEvent.RefreshTags) + } + } + private fun mockMapInitialTagFeedItems() { whenever(readerTagsFeedUiStateMapper.mapInitialPostsUiState(any(), any(), any(), any(), any(), any())) .thenAnswer { @@ -773,4 +913,10 @@ class ReaderTagsFeedViewModelTest : BaseUnitTest() { it?.let { readerNavigationEvents.add(it) } } } + + private fun observeErrorMessageEvents() { + viewModel.errorMessageEvents.observeForever { + it?.let { errorMessageEvents.add(it) } + } + } }