diff --git a/WordPress/build.gradle b/WordPress/build.gradle index 2ac338ca6eca..0a1ebf4622db 100644 --- a/WordPress/build.gradle +++ b/WordPress/build.gradle @@ -152,6 +152,7 @@ android { buildConfigField "boolean", "READER_READING_PREFERENCES", "false" buildConfigField "boolean", "READER_READING_PREFERENCES_FEEDBACK", "false" buildConfigField "boolean", "READER_TAGS_FEED", "false" + buildConfigField "boolean", "READER_ANNOUNCEMENT_CARD", "false" // Override these constants in jetpack product flavor to enable/ disable features buildConfigField "boolean", "ENABLE_SITE_CREATION", "true" diff --git a/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java b/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java index 0396fb813f35..1c472a5e2200 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefs.java @@ -204,6 +204,7 @@ public enum DeletablePrefKey implements PrefKey { SHOULD_HIDE_DYNAMIC_CARD, PINNED_SITE_IDS, READER_READING_PREFERENCES_JSON, + SHOULD_SHOW_READER_ANNOUNCEMENT_CARD, } /** @@ -1780,6 +1781,14 @@ public static void setPinnedSiteLocalIds(@NonNull final String ids) { setString(DeletablePrefKey.PINNED_SITE_IDS, ids); } + public static boolean getShouldShowReaderAnnouncementCard() { + return prefs().getBoolean(DeletablePrefKey.SHOULD_SHOW_READER_ANNOUNCEMENT_CARD.name(), true); + } + + public static void setShouldShowReaderAnnouncementCard(final boolean shouldShow) { + prefs().edit().putBoolean(DeletablePrefKey.SHOULD_SHOW_READER_ANNOUNCEMENT_CARD.name(), shouldShow).apply(); + } + @Nullable public static String getReaderReadingPreferencesJson() { return getString(DeletablePrefKey.READER_READING_PREFERENCES_JSON, null); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefsWrapper.kt b/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefsWrapper.kt index 81714fba6d47..c185a8f8b3e8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefsWrapper.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/prefs/AppPrefsWrapper.kt @@ -453,6 +453,11 @@ class AppPrefsWrapper @Inject constructor() { fun setBookmarkPostsPseudoIdsUpdated() = AppPrefs.setBookmarkPostsPseudoIdsUpdated() + fun shouldShowReaderAnnouncementCard(): Boolean = AppPrefs.getShouldShowReaderAnnouncementCard() + + fun setShouldShowReaderAnnouncementCard(shouldShow: Boolean) = + AppPrefs.setShouldShowReaderAnnouncementCard(shouldShow) + fun getAllPrefs(): Map = AppPrefs.getAllPrefs() fun setString(prefKey: PrefKey, value: String) { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderFragment.kt index 474ef518d722..022c9627faab 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderFragment.kt @@ -53,6 +53,7 @@ import org.wordpress.android.ui.reader.subfilter.SubfilterCategory import org.wordpress.android.ui.reader.subfilter.SubfilterListItem import org.wordpress.android.ui.reader.viewmodels.ReaderViewModel import org.wordpress.android.ui.reader.viewmodels.ReaderViewModel.ReaderUiState.ContentUiState +import org.wordpress.android.ui.reader.views.compose.ReaderAnnouncementCard import org.wordpress.android.ui.reader.views.compose.ReaderTopAppBar import org.wordpress.android.ui.reader.views.compose.filter.ReaderFilterType import org.wordpress.android.ui.utils.UiHelpers @@ -99,6 +100,7 @@ class ReaderFragment : Fragment(R.layout.reader_fragment_layout), ScrollableView override fun onViewCreated(view: View, savedInstanceState: Bundle?) { binding = ReaderFragmentLayoutBinding.bind(view).apply { initTopAppBar() + initAnnouncementCard() initViewModel(savedInstanceState) } } @@ -181,6 +183,23 @@ class ReaderFragment : Fragment(R.layout.reader_fragment_layout), ScrollableView } } + private fun ReaderFragmentLayoutBinding.initAnnouncementCard() { + readerAnnouncementCardComposeView.apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + val announcementCardUiState by viewModel.announcementCardState.observeAsState() + val state = announcementCardUiState ?: return@setContent + AppTheme { + ReaderAnnouncementCard( + shouldShow = state.shouldShow, + items = state.items, + onAnnouncementCardDoneClick = { viewModel.onAnnouncementCardDoneClick() } + ) + } + } + } + } + private fun ReaderFragmentLayoutBinding.initViewModel(savedInstanceState: Bundle?) { viewModel = ViewModelProvider(this@ReaderFragment, viewModelFactory)[ReaderViewModel::class.java] startReaderViewModel(savedInstanceState) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/viewmodels/ReaderViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/viewmodels/ReaderViewModel.kt index 97106e3b3326..14ba95f13dbc 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/viewmodels/ReaderViewModel.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/viewmodels/ReaderViewModel.kt @@ -18,6 +18,7 @@ import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode.MAIN import org.wordpress.android.BuildConfig import org.wordpress.android.R +import org.wordpress.android.analytics.AnalyticsTracker import org.wordpress.android.fluxc.store.AccountStore import org.wordpress.android.fluxc.store.QuickStartStore import org.wordpress.android.fluxc.store.QuickStartStore.QuickStartTask @@ -43,6 +44,7 @@ import org.wordpress.android.ui.reader.utils.DateProvider import org.wordpress.android.ui.reader.utils.ReaderTopBarMenuHelper import org.wordpress.android.ui.reader.viewmodels.ReaderViewModel.ReaderUiState.ContentUiState import org.wordpress.android.ui.reader.viewmodels.ReaderViewModel.ReaderUiState.ContentUiState.TabUiState +import org.wordpress.android.ui.reader.views.compose.ReaderAnnouncementCardItemData import org.wordpress.android.ui.reader.views.compose.filter.ReaderFilterSelectedItem import org.wordpress.android.ui.reader.views.compose.filter.ReaderFilterType import org.wordpress.android.ui.utils.UiString @@ -51,6 +53,7 @@ import org.wordpress.android.util.JetpackBrandingUtils import org.wordpress.android.util.QuickStartUtils import org.wordpress.android.util.SnackbarSequencer import org.wordpress.android.util.UrlUtilsWrapper +import org.wordpress.android.util.config.ReaderAnnouncementCardFeatureConfig import org.wordpress.android.util.config.ReaderTagsFeedFeatureConfig import org.wordpress.android.util.distinct import org.wordpress.android.viewmodel.Event @@ -81,6 +84,7 @@ class ReaderViewModel @Inject constructor( private val urlUtilsWrapper: UrlUtilsWrapper, private val readerTagsFeedFeatureConfig: ReaderTagsFeedFeatureConfig, // todo: annnmarie removed this private val getFollowedTagsUseCase: GetFollowedTagsUseCase + private val readerAnnouncementCardFeatureConfig: ReaderAnnouncementCardFeatureConfig, ) : ScopedViewModel(mainDispatcher) { private var initialized: Boolean = false private var wasPaused: Boolean = false @@ -93,6 +97,9 @@ class ReaderViewModel @Inject constructor( private val _topBarUiState = MutableLiveData() val topBarUiState: LiveData = _topBarUiState.distinct() + private val _announcementCardState = MutableLiveData() + val announcementCardState: LiveData = _announcementCardState + private val _updateTags = MutableLiveData>() val updateTags: LiveData> = _updateTags @@ -125,6 +132,7 @@ class ReaderViewModel @Inject constructor( if (initialized) return loadTabs(savedInstanceState) if (jetpackBrandingUtils.shouldShowJetpackPoweredBottomSheet()) showJetpackPoweredBottomSheet() + updateAnnouncementCard() } fun onSaveInstanceState(out: Bundle) { @@ -138,6 +146,40 @@ class ReaderViewModel @Inject constructor( // _showJetpackPoweredBottomSheet.value = Event(true) } + private fun updateAnnouncementCard() { + val items = mutableListOf() + + if (readerTagsFeedFeatureConfig.isEnabled()) { + items.add( + ReaderAnnouncementCardItemData( + iconRes = R.drawable.ic_reader_tag, + titleRes = R.string.reader_announcement_card_tags_stream_title, + descriptionRes = R.string.reader_announcement_card_tags_stream_description, + ) + ) + } + + items.add( + ReaderAnnouncementCardItemData( + iconRes = R.drawable.ic_reader_preferences, + titleRes = R.string.reader_announcement_card_reading_preferences_title, + descriptionRes = R.string.reader_announcement_card_reading_preferences_description, + ) + ) + + _announcementCardState.value = AnnouncementCardUiState( + shouldShow = readerAnnouncementCardFeatureConfig.isEnabled() && + appPrefsWrapper.shouldShowReaderAnnouncementCard(), + items = items, + ) + } + + fun onAnnouncementCardDoneClick() { + readerTracker.track(AnalyticsTracker.Stat.READER_ANNOUNCEMENT_CARD_DISMISSED) + appPrefsWrapper.setShouldShowReaderAnnouncementCard(false) + updateAnnouncementCard() + } + @JvmOverloads fun loadTabs(savedInstanceState: Bundle? = null) { launch { @@ -563,6 +605,11 @@ class ReaderViewModel @Inject constructor( val duration: Int = QUICK_START_PROMPT_DURATION ) + data class AnnouncementCardUiState( + val shouldShow: Boolean, + val items: List, + ) + companion object { private const val QUICK_START_PROMPT_DURATION = 5000 private const val FILTER_UPDATE_DELAY = 50L diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/views/compose/ReaderAnnouncementCard.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/views/compose/ReaderAnnouncementCard.kt new file mode 100644 index 000000000000..1c4bb3877354 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/views/compose/ReaderAnnouncementCard.kt @@ -0,0 +1,183 @@ +package org.wordpress.android.ui.reader.views.compose + +import android.content.res.Configuration +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.expandIn +import androidx.compose.animation.shrinkOut +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material3.Icon +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.draw.drawBehind +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.wordpress.android.R +import org.wordpress.android.designsystem.footnote +import org.wordpress.android.ui.compose.theme.AppColor +import org.wordpress.android.ui.compose.theme.AppTheme +import org.wordpress.android.ui.compose.unit.Margin + +@Composable +fun ReaderAnnouncementCard( + shouldShow: Boolean, + items: List, + onAnnouncementCardDoneClick: () -> Unit, +) { + val primaryColor = if (isSystemInDarkTheme()) AppColor.White else AppColor.Black + val secondaryColor = if (isSystemInDarkTheme()) AppColor.Black else AppColor.White + AnimatedVisibility( + visible = shouldShow, + enter = expandIn(), + exit = shrinkOut( + shrinkTowards = Alignment.TopCenter, + ), + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(Margin.ExtraLarge.value), + verticalArrangement = Arrangement.spacedBy(Margin.ExtraLarge.value), + ) { + // Title + Text( + text = stringResource(R.string.reader_announcement_card_title), + style = MaterialTheme.typography.labelLarge, + color = primaryColor, + ) + // Items + Column( + modifier = Modifier + .fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(Margin.ExtraLarge.value) + ) { + items.forEach { + ReaderAnnouncementCardItem(it) + } + } + // Done button + Button( + modifier = Modifier + .fillMaxWidth(), + onClick = { onAnnouncementCardDoneClick() }, + elevation = ButtonDefaults.elevation(0.dp), + colors = ButtonDefaults.buttonColors( + backgroundColor = primaryColor, + ), + ) { + Text( + text = stringResource(id = R.string.reader_btn_done), + color = secondaryColor, + style = MaterialTheme.typography.labelLarge, + ) + } + } + } +} + +@Composable +private fun ReaderAnnouncementCardItem(data: ReaderAnnouncementCardItemData) { + val primaryColor = if (isSystemInDarkTheme()) AppColor.White else AppColor.Black + val secondaryColor = if (isSystemInDarkTheme()) AppColor.Black else AppColor.White + Row( + modifier = Modifier + .fillMaxWidth() + .defaultMinSize(minWidth = 54.dp, minHeight = 54.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + val iconBackgroundColor = primaryColor + Icon( + modifier = Modifier + .padding( + start = Margin.Large.value, + end = Margin.Large.value + ) + .drawBehind { + drawCircle( + color = iconBackgroundColor, + radius = this.size.maxDimension, + ) + }, + painter = painterResource(data.iconRes), + tint = secondaryColor, + contentDescription = null + ) + Column(verticalArrangement = Arrangement.Center) { + Text( + modifier = Modifier.padding( + start = Margin.Large.value, + ), + text = stringResource(data.titleRes), + style = MaterialTheme.typography.labelLarge, + color = primaryColor, + ) + val secondaryElementColor = primaryColor.copy( + alpha = 0.6F + ) + Text( + modifier = Modifier.padding( + start = Margin.Large.value, + ), + text = stringResource(data.descriptionRes), + style = MaterialTheme.typography.footnote, + color = secondaryElementColor, + ) + } + } +} + +data class ReaderAnnouncementCardItemData( + @DrawableRes val iconRes: Int, + @StringRes val titleRes: Int, + @StringRes val descriptionRes: Int, +) + + +@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +fun ReaderTagsFeedPostListItemPreview() { + AppTheme { + Box( + modifier = Modifier + .fillMaxWidth() + ) { + ReaderAnnouncementCard( + shouldShow = false, + items = listOf( + ReaderAnnouncementCardItemData( + iconRes = R.drawable.ic_wifi_off_24px, + titleRes = R.string.reader_tags_display_name, + descriptionRes = R.string.reader_tags_feed_loading_error_description, + ), + ReaderAnnouncementCardItemData( + iconRes = R.drawable.ic_wifi_off_24px, + titleRes = R.string.reader_tags_display_name, + descriptionRes = R.string.reader_tags_feed_loading_error_description, + ), + ReaderAnnouncementCardItemData( + iconRes = R.drawable.ic_wifi_off_24px, + titleRes = R.string.reader_tags_display_name, + descriptionRes = R.string.reader_tags_feed_loading_error_description, + ), + ), + onAnnouncementCardDoneClick = {}, + ) + } + } +} diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/TagsAndCategoriesUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/TagsAndCategoriesUseCase.kt index c9503dde80e4..86f2f112a70d 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/TagsAndCategoriesUseCase.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/TagsAndCategoriesUseCase.kt @@ -200,7 +200,7 @@ class TagsAndCategoriesUseCase } private fun getIcon(type: String) = - if (type == "tag") R.drawable.ic_tag_white_24dp else R.drawable.ic_folder_white_24dp + if (type == "tag") R.drawable.ic_reader_tag else R.drawable.ic_folder_white_24dp private fun onLinkClick() { analyticsTracker.track(AnalyticsTracker.Stat.STATS_TAGS_AND_CATEGORIES_VIEW_MORE_TAPPED) diff --git a/WordPress/src/main/java/org/wordpress/android/util/config/ReaderAnnouncementCardFeatureConfig.kt b/WordPress/src/main/java/org/wordpress/android/util/config/ReaderAnnouncementCardFeatureConfig.kt new file mode 100644 index 000000000000..9c9a87bb2645 --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/util/config/ReaderAnnouncementCardFeatureConfig.kt @@ -0,0 +1,15 @@ +package org.wordpress.android.util.config + +import org.wordpress.android.BuildConfig +import org.wordpress.android.annotation.Feature +import javax.inject.Inject + +private const val READER_ANNOUNCEMENT_CARD_REMOTE_FIELD = "reader_announcement_card" +@Feature(remoteField = READER_ANNOUNCEMENT_CARD_REMOTE_FIELD, defaultValue = false) +class ReaderAnnouncementCardFeatureConfig @Inject constructor( + appConfig: AppConfig +) : FeatureConfig( + appConfig, + BuildConfig.READER_ANNOUNCEMENT_CARD, + READER_ANNOUNCEMENT_CARD_REMOTE_FIELD, +) diff --git a/WordPress/src/main/res/drawable/ic_tag_white_24dp.xml b/WordPress/src/main/res/drawable/ic_reader_tag.xml similarity index 100% rename from WordPress/src/main/res/drawable/ic_tag_white_24dp.xml rename to WordPress/src/main/res/drawable/ic_reader_tag.xml diff --git a/WordPress/src/main/res/layout/reader_fragment_layout.xml b/WordPress/src/main/res/layout/reader_fragment_layout.xml index 64d03853edf3..081157fd6aa8 100644 --- a/WordPress/src/main/res/layout/reader_fragment_layout.xml +++ b/WordPress/src/main/res/layout/reader_fragment_layout.xml @@ -18,18 +18,45 @@ - + android:paddingBottom="56dp" + app:layout_behavior="@string/appbar_scrolling_view_behavior"> - + + + + + + + + + - diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index e9ec2d338432..4e6d1540e5e8 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -1709,6 +1709,11 @@ 0 Tags 1 Tag %d Tags + New in Reader + Tags stream + Tap the dropdown at the top and select Tags to access streams from your followed tags. + Reading Preferences + Choose colors and fonts that suit you. When you’re reading a post tap the AA icon at the top of the screen. Reading Preferences reading,colors,fonts diff --git a/WordPress/src/test/java/org/wordpress/android/ui/reader/viewmodels/ReaderViewModelTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/reader/viewmodels/ReaderViewModelTest.kt index 02a0a53f8ed6..06657f8f67ca 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/reader/viewmodels/ReaderViewModelTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/reader/viewmodels/ReaderViewModelTest.kt @@ -42,9 +42,12 @@ import org.wordpress.android.ui.reader.viewmodels.ReaderViewModel.TopBarUiState import org.wordpress.android.util.JetpackBrandingUtils import org.wordpress.android.util.SnackbarSequencer import org.wordpress.android.util.UrlUtilsWrapper +import org.wordpress.android.util.config.ReaderAnnouncementCardFeatureConfig import org.wordpress.android.util.config.ReaderTagsFeedFeatureConfig import org.wordpress.android.viewmodel.Event import java.util.Date +import kotlin.test.assertFalse +import kotlin.test.assertTrue private const val DUMMY_CURRENT_TIME: Long = 10000000000 @@ -89,6 +92,9 @@ class ReaderViewModelTest : BaseUnitTest() { @Mock lateinit var readerTagsFeedFeatureConfig: ReaderTagsFeedFeatureConfig + @Mock + lateinit var readerAnnouncementCardFeatureConfig: ReaderAnnouncementCardFeatureConfig + private val emptyReaderTagList = ReaderTagList() private val nonEmptyReaderTagList = createNonMockedNonEmptyReaderTagList() @@ -112,6 +118,7 @@ class ReaderViewModelTest : BaseUnitTest() { ReaderTopBarMenuHelper(readerTagsFeedFeatureConfig), urlUtilsWrapper, readerTagsFeedFeatureConfig, + readerAnnouncementCardFeatureConfig, ) whenever(dateProvider.getCurrentDate()).thenReturn(Date(DUMMY_CURRENT_TIME)) @@ -502,6 +509,86 @@ class ReaderViewModelTest : BaseUnitTest() { assertThat(showJetpackOverlayEvent.last().peekContent()).isTrue } + @Test + fun `Should load announcement card correctly with tags item`() = testWithNonEmptyTags { + whenever(readerTagsFeedFeatureConfig.isEnabled()).thenReturn(true) + + triggerContentDisplay() + val observers = initObservers() + + val announcementCardUiState = observers.announcementCardStateEvents.first() + + assertThat(announcementCardUiState.items).hasSize(2) + + val tagsFeedItem = announcementCardUiState.items[0] + assertThat(tagsFeedItem.iconRes).isEqualTo(R.drawable.ic_reader_tag) + assertThat(tagsFeedItem.titleRes).isEqualTo(R.string.reader_announcement_card_tags_stream_title) + assertThat(tagsFeedItem.descriptionRes).isEqualTo(R.string.reader_announcement_card_tags_stream_description) + + val readerPreferencesItem = announcementCardUiState.items[1] + assertThat(readerPreferencesItem.iconRes).isEqualTo(R.drawable.ic_reader_preferences) + assertThat(readerPreferencesItem.titleRes).isEqualTo( + R.string.reader_announcement_card_reading_preferences_title + ) + assertThat(readerPreferencesItem.descriptionRes).isEqualTo( + R.string.reader_announcement_card_reading_preferences_description + ) + } + + @Test + fun `Should load announcement card correctly without tags item`() = testWithNonEmptyTags { + whenever(readerTagsFeedFeatureConfig.isEnabled()).thenReturn(false) + + triggerContentDisplay() + val observers = initObservers() + + val announcementCardUiState = observers.announcementCardStateEvents.first() + + assertThat(announcementCardUiState.items).hasSize(1) + + val readerPreferencesItem = announcementCardUiState.items[0] + assertThat(readerPreferencesItem.iconRes).isEqualTo(R.drawable.ic_reader_preferences) + assertThat(readerPreferencesItem.titleRes).isEqualTo( + R.string.reader_announcement_card_reading_preferences_title + ) + assertThat(readerPreferencesItem.descriptionRes).isEqualTo( + R.string.reader_announcement_card_reading_preferences_description + ) + } + + @Test + fun `Should show announcement card if feature flag is enabled and app preference returns true`() = + testWithNonEmptyTags { + whenever(readerAnnouncementCardFeatureConfig.isEnabled()).thenReturn(true) + whenever(appPrefsWrapper.shouldShowReaderAnnouncementCard()).thenReturn(true) + triggerContentDisplay() + val observers = initObservers() + + val announcementCardUiState = observers.announcementCardStateEvents.first() + assertTrue(announcementCardUiState.shouldShow) + } + + @Test + fun `Should NOT show announcement card if feature flag is disabled`() = testWithNonEmptyTags { + whenever(readerAnnouncementCardFeatureConfig.isEnabled()).thenReturn(false) + triggerContentDisplay() + val observers = initObservers() + + val announcementCardUiState = observers.announcementCardStateEvents.first() + assertFalse(announcementCardUiState.shouldShow) + } + + @Test + fun `Should NOT show announcement card if app preference returns false`() = testWithNonEmptyTags { + whenever(readerAnnouncementCardFeatureConfig.isEnabled()).thenReturn(true) + whenever(appPrefsWrapper.shouldShowReaderAnnouncementCard()).thenReturn(false) + triggerContentDisplay() + val observers = initObservers() + + val announcementCardUiState = observers.announcementCardStateEvents.first() + assertFalse(announcementCardUiState.shouldShow) + } + private fun assertQsFollowSiteTaskStarted( observers: Observers, isSettingsSupported: Boolean = true @@ -546,13 +633,19 @@ class ReaderViewModelTest : BaseUnitTest() { // tabNavigationEvents.add(it.peekContent()) // } - return Observers(uiStates, quickStartReaderPrompts, tabNavigationEvents) + val announcementCardStateEvents = mutableListOf() + viewModel.announcementCardState.observeForever { + announcementCardStateEvents.add(it) + } + + return Observers(uiStates, quickStartReaderPrompts, tabNavigationEvents, announcementCardStateEvents) } private data class Observers( val uiStates: List, val quickStartReaderPrompts: List>, - val tabNavigationEvents: List + val tabNavigationEvents: List, + val announcementCardStateEvents: List, ) private fun triggerContentDisplay( diff --git a/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/TagsAndCategoriesUseCaseTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/TagsAndCategoriesUseCaseTest.kt index 264262dd7f86..cc3cf536c3cc 100644 --- a/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/TagsAndCategoriesUseCaseTest.kt +++ b/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/lists/sections/insights/usecases/TagsAndCategoriesUseCaseTest.kt @@ -246,7 +246,7 @@ class TagsAndCategoriesUseCaseTest : BaseUnitTest() { } else { assertThat(item.barWidth).isNull() } - assertThat(item.icon).isEqualTo(R.drawable.ic_tag_white_24dp) + assertThat(item.icon).isEqualTo(R.drawable.ic_reader_tag) assertThat(item.contentDescription).isEqualTo(contentDescription) } diff --git a/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java b/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java index c1bab072d19f..9f2d53fd5e7c 100644 --- a/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java +++ b/libs/analytics/src/main/java/org/wordpress/android/analytics/AnalyticsTracker.java @@ -88,6 +88,7 @@ public enum Stat { READER_READING_PREFERENCES_FEEDBACK_TAPPED, READER_READING_PREFERENCES_ITEM_TAPPED, READER_READING_PREFERENCES_SAVED, + READER_ANNOUNCEMENT_CARD_DISMISSED, READER_TAGS_FEED_HEADER_TAPPED, READER_TAGS_FEED_MORE_FROM_TAG_TAPPED, STATS_ACCESSED,