[Reader] Implement Tags IA feature flag

Fixes #20595

-----

## To Test:

- Install JP and sign in.
- Enable remote feature `reader_tags_feed`.
- Open "Reader".
- 🔍  Open the dropdown menu: "Tags" feed should be in the list.
- Disable remote feature `reader_tags_feed`.
- Restart the app.
- 🔍 Open "Reader" and dropdown menu: "Tags" feed should **not** be in the list.

-----

## Regression Notes

1. Potential unintended areas of impact

    - None.

2. What I did to test those areas of impact (or what existing automated tests I relied on)

    - Manual testing.

3. What automated tests I added (or what prevented me from doing so)

    --

-----

## PR Submission Checklist:

- [x] I have completed the Regression Notes.
- [x] I have considered adding accessibility improvements for my changes.
- [x] I have considered if this change warrants user-facing release notes and have added them to `RELEASE-NOTES.txt` if necessary.

-----

## Testing Checklist (strike-out the not-applying and unnecessary ones):

- [ ] WordPress.com sites and self-hosted Jetpack sites.
- [ ] Portrait and landscape orientations.
- [ ] Light and dark modes.
- [ ] Fonts: Larger, smaller and bold text.
- [ ] High contrast.
- [ ] Talkback.
- [ ] Languages with large words or with letters/accents not frequently used in English.
- [ ] Right-to-left languages. (Even if translation isn’t complete, formatting should still respect the right-to-left layout)
- [ ] Large and small screen sizes. (Tablet and smaller phones)
- [ ] Multi-tasking: Split screen and Pop-up view. (Android 10 or higher)

[Reader] Implement feature flag for tags IA
- Only display "Tags" feed item if the FF is enabled.
- Only hide the "Tags" chip from "Subscriptions" feed if the FF is enabled.

Thanks for reporting! 👍 <!-- generated_by_dangermattic -->

diff --git a/WordPress/build.gradle b/WordPress/build.gradle
index e3f33b5c6cf4..8b9c6ad61d76 100644
--- a/WordPress/build.gradle
+++ b/WordPress/build.gradle
@@ -150,6 +150,7 @@ android {
         buildConfigField "boolean", "READER_DISCOVER_NEW_ENDPOINT", "false"
         buildConfigField "boolean", "READER_READING_PREFERENCES", "false"
         buildConfigField "boolean", "READER_READING_PREFERENCES_FEEDBACK", "false"
+        buildConfigField "boolean", "READER_TAGS_FEED", "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/reader/utils/ReaderTopBarMenuHelper.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelper.kt
index 466c642f271f..ba94c014f5c5 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelper.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelper.kt
@@ -10,10 +10,13 @@ import org.wordpress.android.models.ReaderTagList
 import org.wordpress.android.models.ReaderTagType
 import org.wordpress.android.ui.compose.components.menu.dropdown.MenuElementData
 import org.wordpress.android.ui.utils.UiString
+import org.wordpress.android.util.config.ReaderTagsFeedFeatureConfig
 import org.wordpress.android.util.extensions.indexOrNull
 import javax.inject.Inject

-class ReaderTopBarMenuHelper @Inject constructor() {
+class ReaderTopBarMenuHelper @Inject constructor(
+    private val readerTagsFeedFeatureConfig: ReaderTagsFeedFeatureConfig
+) {
     fun createMenu(readerTagsList: ReaderTagList): List<MenuElementData> {
         return mutableListOf<MenuElementData>().apply {
             readerTagsList.indexOrNull { it.isDiscover }?.let { discoverIndex ->
@@ -37,8 +40,10 @@ class ReaderTopBarMenuHelper @Inject constructor() {
                     text = readerTagsList[followedP2sIndex].tagTitle,
                 ))
             }
-            readerTagsList.indexOrNull { it.isTags }?.let { tagsIndex ->
-                add(createTagsItem(getMenuItemIdFromReaderTagIndex(tagsIndex)))
+            if (readerTagsFeedFeatureConfig.isEnabled()) {
+                readerTagsList.indexOrNull { it.isTags }?.let { tagsIndex ->
+                    add(createTagsItem(getMenuItemIdFromReaderTagIndex(tagsIndex)))
+                }
             }
             readerTagsList
                 .foldIndexed(SparseArrayCompat<ReaderTag>()) { index, sparseArray, readerTag ->
diff --git a/WordPress/src/main/java/org/wordpress/android/util/config/ReaderTagsFeedFeatureConfig.kt b/WordPress/src/main/java/org/wordpress/android/util/config/ReaderTagsFeedFeatureConfig.kt
new file mode 100644
index 000000000000..a41e596b5b2f
--- /dev/null
+++ b/WordPress/src/main/java/org/wordpress/android/util/config/ReaderTagsFeedFeatureConfig.kt
@@ -0,0 +1,16 @@
+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_TAGS_FEED_REMOTE_FIELD = "reader_tags_feed"
+
+@Feature(remoteField = READER_TAGS_FEED_REMOTE_FIELD, defaultValue = false)
+class ReaderTagsFeedFeatureConfig @Inject constructor(
+    appConfig: AppConfig
+) : FeatureConfig(
+    appConfig,
+    BuildConfig.READER_TAGS_FEED,
+    READER_TAGS_FEED_REMOTE_FIELD,
+)

diff --git a/WordPress/src/test/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelperTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelperTest.kt
index 0279f25bee2d..03e57616424e 100644
--- a/WordPress/src/test/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelperTest.kt
+++ b/WordPress/src/test/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelperTest.kt
@@ -4,6 +4,7 @@ import org.assertj.core.api.Assertions.assertThat
 import org.junit.Test
 import org.mockito.kotlin.doReturn
 import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
 import org.wordpress.android.R
 import org.wordpress.android.models.ReaderTag
 import org.wordpress.android.models.ReaderTagList
@@ -11,12 +12,18 @@ import org.wordpress.android.models.ReaderTagType
 import org.wordpress.android.ui.compose.components.menu.dropdown.MenuElementData
 import org.wordpress.android.ui.utils.UiString.UiStringRes
 import org.wordpress.android.ui.utils.UiString.UiStringText
+import org.wordpress.android.util.config.ReaderTagsFeedFeatureConfig

 class ReaderTopBarMenuHelperTest {
-    val helper = ReaderTopBarMenuHelper()
+    private val readerTagsFeedFeatureConfig: ReaderTagsFeedFeatureConfig = mock()
+    val helper = ReaderTopBarMenuHelper(
+        readerTagsFeedFeatureConfig = readerTagsFeedFeatureConfig
+    )

     @Test
-    fun `GIVEN all tags are available WHEN createMenu THEN all items are created correctly`() {
+    fun `GIVEN all tags are available and tags FF disabled WHEN createMenu THEN all items are created correctly`() {
+        whenever(readerTagsFeedFeatureConfig.isEnabled()).thenReturn(false)
+
         val tags = ReaderTagList().apply {
             add(mockFollowingTag()) // item 0
             add(mockDiscoverTag()) // item 1
@@ -65,6 +72,62 @@ class ReaderTopBarMenuHelperTest {
         assertThat(customList3Item.text).isEqualTo(UiStringText("custom-list-3"))
     }

+    @Test
+    fun `GIVEN all tags are available and tags FF enabled WHEN createMenu THEN all items are created correctly`() {
+        whenever(readerTagsFeedFeatureConfig.isEnabled()).thenReturn(true)
+
+        val tags = ReaderTagList().apply {
+            add(mockFollowingTag()) // item 0
+            add(mockDiscoverTag()) // item 1
+            add(mockSavedTag()) // item 2
+            add(mockLikedTag()) // item 3
+            add(mockTagsTag()) // item 4
+            add(mockA8CTag()) // item 5
+            add(mockFollowedP2sTag()) // item 6
+            add(createCustomListTag("custom-list-1")) // item 7
+            add(createCustomListTag("custom-list-2")) // item 8
+            add(createCustomListTag("custom-list-3")) // item 9
+        }
+
+        val menu = helper.createMenu(tags)
+
+        // compare the menu items one by one to check their indices
+        val discoverItem = menu.findSingleItem { it.id == "1" }!!
+        assertThat(discoverItem.text).isEqualTo(UiStringRes(R.string.reader_dropdown_menu_discover))
+
+        val subscriptionsItem = menu.findSingleItem { it.id == "0" }!!
+        assertThat(subscriptionsItem.text).isEqualTo(UiStringRes(R.string.reader_dropdown_menu_subscriptions))
+
+        val savedItem = menu.findSingleItem { it.id == "2" }!!
+        assertThat(savedItem.text).isEqualTo(UiStringRes(R.string.reader_dropdown_menu_saved))
+
+        val likedItem = menu.findSingleItem { it.id == "3" }!!
+        assertThat(likedItem.text).isEqualTo(UiStringRes(R.string.reader_dropdown_menu_liked))
+
+        val tagsItem = menu.findSingleItem { it.id == "4" }!!
+        assertThat(tagsItem.text).isEqualTo(UiStringRes(R.string.reader_dropdown_menu_tags))
+
+        val a8cItem = menu.findSingleItem { it.id == "5" }!!
+        assertThat(a8cItem.text).isEqualTo(UiStringRes(R.string.reader_dropdown_menu_automattic))
+
+        val followedP2sItem = menu.findSingleItem { it.id == "6" }!!
+        assertThat(followedP2sItem.text).isEqualTo(UiStringText("Followed P2s"))
+
+        assertThat(menu).contains(MenuElementData.Divider)
+
+        val customListsItem = menu.findSubMenu()!!
+        assertThat(customListsItem.text).isEqualTo(UiStringRes(R.string.reader_dropdown_menu_lists))
+
+        val customList1Item = customListsItem.children.findSingleItem { it.id == "7" }!!
+        assertThat(customList1Item.text).isEqualTo(UiStringText("custom-list-1"))
+
+        val customList2Item = customListsItem.children.findSingleItem { it.id == "8" }!!
+        assertThat(customList2Item.text).isEqualTo(UiStringText("custom-list-2"))
+
+        val customList3Item = customListsItem.children.findSingleItem { it.id == "9" }!!
+        assertThat(customList3Item.text).isEqualTo(UiStringText("custom-list-3"))
+    }
+
     @Test
     fun `GIVEN discover not present WHEN createMenu THEN discover menu item not created`() {
         val tags = ReaderTagList().apply {
@@ -275,6 +338,12 @@ class ReaderTopBarMenuHelperTest {
         }
     }

+    private fun mockTagsTag(): ReaderTag {
+        return mock {
+            on { isTags } doReturn true
+        }
+    }
+
     private fun createCustomListTag(title: String): ReaderTag {
         return ReaderTag(
             title,
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 bc6e73735645..bb9c557587bd 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,6 +42,7 @@ 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.ReaderTagsFeedFeatureConfig
 import org.wordpress.android.viewmodel.Event
 import java.util.Date

@@ -85,7 +86,9 @@ class ReaderViewModelTest : BaseUnitTest() {
     @Mock
     lateinit var jetpackFeatureRemovalOverlayUtil: JetpackFeatureRemovalOverlayUtil

-    private val readerTopBarMenuHelper: ReaderTopBarMenuHelper = ReaderTopBarMenuHelper()
+    private val readerTagsFeedFeatureConfig: ReaderTagsFeedFeatureConfig = mock()
+
+    private val readerTopBarMenuHelper: ReaderTopBarMenuHelper = ReaderTopBarMenuHelper(readerTagsFeedFeatureConfig)

     private val emptyReaderTagList = ReaderTagList()


[Reader] Add "Tags" to dropdown menu

Fixes #20576

-----

## To Test:

- Install JP and sign in.
- Open "Reader".
- 🔍 Open the dropdown menu: there should be a "Tags" item with the correct icon (design: p1712144397494019/1712076563.723409-slack-C05N140C8H5)
<img width="198" alt="image" src="https://github.com/wordpress-mobile/WordPress-Android/assets/14964993/4f9306ec-cffd-4f0d-9434-caf318674c7a">

- 🔍 Tap the "Tags" item: an empty screen should be loaded (empty state and posts lists will be handled in separate tickets).
- 🔍 Open the other feed items: they should be working as expected.
- 🔍 Inspect the local DB: the "Tags" item only exists in memory, so it shouldn't be added to the local DB.
- 🔍 Create a new custom list in the web "Reader" and verify it's shown in the app to make sure the back-end integration is still working as expected.

-----

## Regression Notes

1. Potential unintended areas of impact

    - None.

2. What I did to test those areas of impact (or what existing automated tests I relied on)

    - Manual testing.

3. What automated tests I added (or what prevented me from doing so)

    --

-----

## PR Submission Checklist:

- [x] I have completed the Regression Notes.
- [x] I have considered adding accessibility improvements for my changes.
- [x] I have considered if this change warrants user-facing release notes and have added them to `RELEASE-NOTES.txt` if necessary.

-----

## Testing Checklist (strike-out the not-applying and unnecessary ones):

- [ ] WordPress.com sites and self-hosted Jetpack sites.
- [ ] Portrait and landscape orientations.
- [ ] Light and dark modes.
- [ ] Fonts: Larger, smaller and bold text.
- [ ] High contrast.
- [ ] Talkback.
- [ ] Languages with large words or with letters/accents not frequently used in English.
- [ ] Right-to-left languages. (Even if translation isn’t complete, formatting should still respect the right-to-left layout)
- [ ] Large and small screen sizes. (Tablet and smaller phones)
- [ ] Multi-tasking: Split screen and Pop-up view. (Android 10 or higher)

[Reader] Add "Tags" item do dropdown menu
![Image](https://github.com/wordpress-mobile/WordPress-Android/assets/14964993/fb11745b-0d19-4461-bd12-3a4cec93da3e)

diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderTag.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderTag.java
index a8e8018e9814..dbd7b537e8cf 100644
--- a/WordPress/src/main/java/org/wordpress/android/models/ReaderTag.java
+++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderTag.java
@@ -184,6 +184,10 @@ public boolean isBookmarked() {
         return tagType == ReaderTagType.BOOKMARKED;
     }

+    public boolean isTags() {
+        return tagType == ReaderTagType.TAGS;
+    }
+
     public boolean isDiscover() {
         return tagType == ReaderTagType.DEFAULT && getEndpoint().endsWith(DISCOVER_PATH);
     }
diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderTagType.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderTagType.java
index d7d84f191168..cb3486efc523 100644
--- a/WordPress/src/main/java/org/wordpress/android/models/ReaderTagType.java
+++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderTagType.java
@@ -7,7 +7,8 @@ public enum ReaderTagType {
     CUSTOM_LIST,
     SEARCH,
     INTERESTS,
-    DISCOVER_POST_CARDS;
+    DISCOVER_POST_CARDS,
+    TAGS;

     private static final int INT_DEFAULT = 0;
     private static final int INT_FOLLOWED = 1;
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/usecases/LoadReaderTabsUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/usecases/LoadReaderItemsUseCase.kt
similarity index 59%
rename from WordPress/src/main/java/org/wordpress/android/ui/reader/usecases/LoadReaderTabsUseCase.kt
rename to WordPress/src/main/java/org/wordpress/android/ui/reader/usecases/LoadReaderItemsUseCase.kt
index e6d6aea13e5c..0194392aa29d 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/reader/usecases/LoadReaderTabsUseCase.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/usecases/LoadReaderItemsUseCase.kt
@@ -3,24 +3,29 @@ package org.wordpress.android.ui.reader.usecases
 import dagger.Reusable
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.withContext
+import org.wordpress.android.R
 import org.wordpress.android.datasets.ReaderTagTable
+import org.wordpress.android.models.ReaderTag
 import org.wordpress.android.models.ReaderTagList
+import org.wordpress.android.models.ReaderTagType
 import org.wordpress.android.models.containsFollowingTag
 import org.wordpress.android.modules.BG_THREAD
 import org.wordpress.android.ui.reader.utils.ReaderUtils
 import org.wordpress.android.ui.reader.utils.ReaderUtilsWrapper
+import org.wordpress.android.util.StringProvider
 import javax.inject.Inject
 import javax.inject.Named

 /**
- * Loads list of tags that should be displayed as tabs in the entry-point Reader screen.
+ * Loads list of items that should be displayed in the Reader dropdown menu.
  */
 @Reusable
-class LoadReaderTabsUseCase @Inject constructor(
+class LoadReaderItemsUseCase @Inject constructor(
     @Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher,
-    private val readerUtilsWrapper: ReaderUtilsWrapper
+    private val readerUtilsWrapper: ReaderUtilsWrapper,
+    private val stringProvider: StringProvider,
 ) {
-    suspend fun loadTabs(): ReaderTagList {
+    suspend fun load(): ReaderTagList {
         return withContext(bgDispatcher) {
             val tagList = ReaderTagTable.getDefaultTags()

@@ -28,9 +33,18 @@ class LoadReaderTabsUseCase @Inject constructor(
             for users who created custom lists in the past.*/
             tagList.addAll(ReaderTagTable.getCustomListTags())

-            tagList.addAll(ReaderTagTable.getBookmarkTags()) // Add "Saved" tab manually
+            tagList.addAll(ReaderTagTable.getBookmarkTags()) // Add "Saved" item manually

-            // Add "Following" tab manually when on self-hosted site
+            // Add "Tags" item manually
+            tagList.add(ReaderTag(
+                "",
+                stringProvider.getString(R.string.reader_tags_display_name),
+                stringProvider.getString(R.string.reader_tags_display_name),
+                "",
+                ReaderTagType.TAGS
+            ))
+
+            // Add "Subscriptions" item manually when on self-hosted site
             if (!tagList.containsFollowingTag()) {
                 tagList.add(readerUtilsWrapper.getDefaultTagFromDbOrCreateInMemory())
             }
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelper.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelper.kt
index 26e2f876a83c..466c642f271f 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelper.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderTopBarMenuHelper.kt
@@ -37,6 +37,9 @@ class ReaderTopBarMenuHelper @Inject constructor() {
                     text = readerTagsList[followedP2sIndex].tagTitle,
                 ))
             }
+            readerTagsList.indexOrNull { it.isTags }?.let { tagsIndex ->
+                add(createTagsItem(getMenuItemIdFromReaderTagIndex(tagsIndex)))
+            }
             readerTagsList
                 .foldIndexed(SparseArrayCompat<ReaderTag>()) { index, sparseArray, readerTag ->
                     if (readerTag.tagType == ReaderTagType.CUSTOM_LIST) {
@@ -98,6 +101,14 @@ class ReaderTopBarMenuHelper @Inject constructor() {
         )
     }

+    private fun createTagsItem(id: String): MenuElementData.Item.Single {
+        return MenuElementData.Item.Single(
+            id = id,
+            text = UiString.UiStringRes(R.string.reader_dropdown_menu_tags),
+            leadingIcon = R.drawable.ic_reader_tags_24dp,
+        )
+    }
+
     private fun createCustomListsItem(customLists: SparseArrayCompat<ReaderTag>): MenuElementData.Item.SubMenu {
         val customListsMenuItems = mutableListOf<MenuElementData.Item.Single>()
         customLists.forEach { index, readerTag ->
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 5806d169043a..71da3851da95 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
@@ -39,7 +39,7 @@ import org.wordpress.android.ui.reader.subfilter.SubfilterListItem
 import org.wordpress.android.ui.reader.tracker.ReaderTab
 import org.wordpress.android.ui.reader.tracker.ReaderTracker
 import org.wordpress.android.ui.reader.tracker.ReaderTrackerType.MAIN_READER
-import org.wordpress.android.ui.reader.usecases.LoadReaderTabsUseCase
+import org.wordpress.android.ui.reader.usecases.LoadReaderItemsUseCase
 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
@@ -69,7 +69,7 @@ class ReaderViewModel @Inject constructor(
     @Named(BG_THREAD) private val bgDispatcher: CoroutineDispatcher,
     private val appPrefsWrapper: AppPrefsWrapper,
     private val dateProvider: DateProvider,
-    private val loadReaderTabsUseCase: LoadReaderTabsUseCase,
+    private val loadReaderItemsUseCase: LoadReaderItemsUseCase,
     private val readerTracker: ReaderTracker,
     private val accountStore: AccountStore,
     private val quickStartRepository: QuickStartRepository,
@@ -140,7 +140,7 @@ class ReaderViewModel @Inject constructor(
     @JvmOverloads
     fun loadTabs(savedInstanceState: Bundle? = null) {
         launch {
-            val tagList = loadReaderTabsUseCase.loadTabs()
+            val tagList = loadReaderItemsUseCase.load()
             if (tagList.isNotEmpty() && readerTagsList != tagList) {
                 updateReaderTagsList(tagList)
                 updateTopBarUiState(savedInstanceState)
diff --git a/WordPress/src/main/res/drawable/ic_reader_tags_24dp.xml b/WordPress/src/main/res/drawable/ic_reader_tags_24dp.xml
new file mode 100644
index 000000000000..66e347a7ec51
--- /dev/null
+++ b/WordPress/src/main/res/drawable/ic_reader_tags_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M20.1,11.2L13.4,4.5C13.3,4.4 13.1,4.3 12.9,4.3H5C4.6,4.2 4.2,4.6 4.2,5V12.8C4.2,13 4.3,13.2 4.4,13.3L11.1,20C11.3,20.2 11.6,20.4 11.8,20.5C12,20.6 12.4,20.7 12.7,20.7C13,20.7 13.3,20.6 13.6,20.5C13.9,20.4 14.1,20.2 14.4,20L20,14.4C20.4,14 20.7,13.4 20.7,12.8C20.8,12.2 20.5,11.6 20.1,11.2ZM19,13.4L13.4,19C13.3,19.1 13.2,19.1 13.1,19.2C12.9,19.3 12.7,19.3 12.5,19.2C12.4,19.2 12.3,19.1 12.2,19L5.7,12.5V5.8H12.5L19,12.3C19.2,12.5 19.2,12.7 19.2,12.9C19.2,13 19.2,13.2 19,13.4ZM9,8C8.4,8 8,8.4 8,9C8,9.6 8.4,10 9,10C9.6,10 10,9.6 10,9C10,8.4 9.6,8 9,8Z"
+      android:fillColor="#000000"/>
+</vector>
diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml
index a98f8033b020..6969e14b0513 100644
--- a/WordPress/src/main/res/values/strings.xml
+++ b/WordPress/src/main/res/values/strings.xml
@@ -1690,6 +1690,7 @@
     <string name="reader_dropdown_menu_saved">Saved</string>
     <string name="reader_dropdown_menu_liked">Liked</string>
     <string name="reader_dropdown_menu_automattic">Automattic</string>
+    <string name="reader_dropdown_menu_tags">Tags</string>
     <string name="reader_dropdown_menu_lists">Lists</string>
     <string name="reader_filter_chip_blog_zero">0 Blogs</string>
     <string name="reader_filter_chip_blog_one">1 Blog</string>
@@ -2104,6 +2105,7 @@
     <string name="reader_discover_display_name">Discover</string>
     <string name="reader_my_likes_display_name">Likes</string>
     <string name="reader_subscribed_display_name">Subscribed</string>
+    <string name="reader_tags_display_name">Tags</string>

     <!-- timespan shown for posts/comments published within the past 60 seconds -->
     <string name="timespan_now" tools:ignore="UnusedResources">now</string>

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 2f437f24465c..bc6e73735645 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
@@ -33,7 +33,7 @@ import org.wordpress.android.ui.quickstart.QuickStartEvent
 import org.wordpress.android.ui.quickstart.QuickStartType
 import org.wordpress.android.ui.reader.utils.ReaderTopBarMenuHelper
 import org.wordpress.android.ui.reader.tracker.ReaderTracker
-import org.wordpress.android.ui.reader.usecases.LoadReaderTabsUseCase
+import org.wordpress.android.ui.reader.usecases.LoadReaderItemsUseCase
 import org.wordpress.android.ui.reader.utils.DateProvider
 import org.wordpress.android.ui.reader.viewmodels.ReaderViewModel.QuickStartReaderPrompt
 import org.wordpress.android.ui.reader.viewmodels.ReaderViewModel.ReaderUiState
@@ -59,7 +59,7 @@ class ReaderViewModelTest : BaseUnitTest() {
     lateinit var dateProvider: DateProvider

     @Mock
-    lateinit var loadReaderTabsUseCase: LoadReaderTabsUseCase
+    lateinit var loadReaderItemsUseCase: LoadReaderItemsUseCase

     @Mock
     lateinit var readerTracker: ReaderTracker
@@ -100,7 +100,7 @@ class ReaderViewModelTest : BaseUnitTest() {
             testDispatcher(),
             appPrefsWrapper,
             dateProvider,
-            loadReaderTabsUseCase,
+            loadReaderItemsUseCase,
             readerTracker,
             accountStore,
             quickStartRepository,
@@ -156,7 +156,7 @@ class ReaderViewModelTest : BaseUnitTest() {
         viewModel.uiState.observeForever {
             state = it
         }
-        whenever(loadReaderTabsUseCase.loadTabs()).thenReturn(ReaderTagList())
+        whenever(loadReaderItemsUseCase.load()).thenReturn(ReaderTagList())
         // Act
         triggerContentDisplay()
         // Assert
@@ -562,14 +562,14 @@ class ReaderViewModelTest : BaseUnitTest() {

     private fun <T> testWithEmptyTags(block: suspend CoroutineScope.() -> T) {
         test {
-            whenever(loadReaderTabsUseCase.loadTabs()).thenReturn(emptyReaderTagList)
+            whenever(loadReaderItemsUseCase.load()).thenReturn(emptyReaderTagList)
             block()
         }
     }

     private fun <T> testWithNonEmptyTags(block: suspend CoroutineScope.() -> T) {
         test {
-            whenever(loadReaderTabsUseCase.loadTabs()).thenReturn(nonEmptyReaderTagList)
+            whenever(loadReaderItemsUseCase.load()).thenReturn(nonEmptyReaderTagList)
             block()
         }
     }
@@ -579,7 +579,7 @@ class ReaderViewModelTest : BaseUnitTest() {
         block: suspend CoroutineScope.() -> T
     ) {
         test {
-            whenever(loadReaderTabsUseCase.loadTabs()).thenReturn(readerTags)
+            whenever(loadReaderItemsUseCase.load()).thenReturn(readerTags)
             block()
         }
     }


Change "∞" symbol with "100%" on stats

Fixes #17314

This changes "∞" symbol with "100%" on stats. The issue description states removing "∞" symbol but this PR changes it to "%100" and matches this behavior with the web.

|before|after|
|-|-|
|||
|||

-----

## To Test:

1. Log in.
2. Open "My Site → Stats"
3. Select the INSIGHTS tab.
4. Select a date that has 0 views for the previous date on Views & Visitors card.
5. Verify that the data shows "%100" instead of "∞".
6. Repeat the same test for total cards.
7. Repeat the same test for the Overview card on granular tabs.

-----

## Regression Notes

1. Potential unintended areas of impact

    - None

2. What I did to test those areas of impact (or what existing automated tests I relied on)

    - N/A

3. What automated tests I added (or what prevented me from doing so)

    - Updated `StatsUtilsTest`.

-----

## PR Submission Checklist:

- [x] I have completed the Regression Notes.
- [x] I have considered adding accessibility improvements for my changes.
- [x] I have considered if this change warrants user-facing release notes and have added them to `RELEASE-NOTES.txt` if necessary.

-----

## Testing Checklist (strike-out the not-applying and unnecessary ones):

- [ ] ~WordPress.com sites and self-hosted Jetpack sites.~
- [ ] ~Portrait and landscape orientations.~
- [ ] ~Light and dark modes.~
- [ ] ~Fonts: Larger, smaller and bold text.~
- [ ] ~High contrast.~
- [ ] ~Talkback.~
- [ ] ~Languages with large words or with letters/accents not frequently used in English.~
- [ ] ~Right-to-left languages. (Even if translation isn’t complete, formatting should still respect the right-to-left layout)~
- [ ] ~Large and small screen sizes. (Tablet and smaller phones)~
- [ ] ~Multi-tasking: Split screen and Pop-up view. (Android 10 or higher)~

"(∞)" shouldn't be used for infinite percentages in stats screens
### Expected behavior
When the percentage is `∞` for data in stats screens, we should only show the increase.

### Actual behavior
When the percentage is `∞` for data in stats screens, it shows `(∞)`.

### Steps to reproduce the behavior
1. Launch the Jetpack app. (WordPress app has the same issue too, but Jetpack has more places showing `(∞)`.)
2. Open Stats from "My Site → HOME → Stats" it "My Site → MENU → Stats".
3. If the Views & Visitors card is not added to the screen, add it by using ⚙ button at the top end of the screen.
4. Find a case which "Previous Week" had 0 views, and "This week" has more than 0 views.
5. Notice `(∞)` is being shown as the percentage.

The problem is also on Total Likes card, Total Comments card, and the bar chart on DAYS, WEEKS, MONTHS, YEARS tabs.

##### Tested on Pixel 4 emulator, Android 11.0, WPAndroid 20.9-rc-2

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 47aded33e692..7cb01b15dcad 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -4,6 +4,7 @@
 -----
 * [**] Block editor: Highlight text fixes [https://github.com/WordPress/gutenberg/pull/57650]
 * [*] Block editor: Fixes an Aztec editor crash occurring on some occasions when the keyboard suggestions are used [https://github.com/wordpress-mobile/WordPress-Android/pull/20518]
+* [*] [Jetpack-only] Change "∞" symbol with "100%" on stats [https://github.com/wordpress-mobile/WordPress-Android/pull/20564]

 24.5
 -----
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/StatsUtils.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/StatsUtils.kt
index 3f14f0dc1b86..5b66e38a6be7 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/StatsUtils.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/StatsUtils.kt
@@ -226,7 +226,7 @@ class StatsUtils @Inject constructor(
             val difference = value - previousValue
             val percentage = when (previousValue) {
                 value -> "0"
-                0L -> "∞"
+                0L -> percentFormatter.format(value = 100)
                 else -> {
                     val percentageValue = difference.toFloat() / previousValue
                     percentFormatter.format(value = percentageValue, rounding = HALF_UP)

diff --git a/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/utils/StatsUtilsTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/utils/StatsUtilsTest.kt
index 4367ff9d59ea..c875d6565ecc 100644
--- a/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/utils/StatsUtilsTest.kt
+++ b/WordPress/src/test/java/org/wordpress/android/ui/stats/refresh/utils/StatsUtilsTest.kt
@@ -278,12 +278,12 @@ class StatsUtilsTest {

     @Test
     fun `build change with infinite positive difference`() {
-        whenever(percentFormatter.format(value = 3.0F, rounding = HALF_UP)).thenReturn("∞")
+        whenever(percentFormatter.format(100)).thenReturn("100")
         val previousValue = 0L
         val value = 20L
         val positive = true
-        val expectedChange = "+20 (∞%)"
-        whenever(resourceProvider.getString(eq(R.string.stats_traffic_increase), eq("20"), eq("∞")))
+        val expectedChange = "+20 (100%)"
+        whenever(resourceProvider.getString(eq(R.string.stats_traffic_increase), eq("20"), eq("100")))
             .thenReturn(expectedChange)

         val change = statsUtils.buildChange(previousValue, value, positive, isFormattedNumber = true)


Fix open traffic tab from today's stats card

Fixes #20487

This updates Today's Stats card to have it open "By day" granularity.

-----

## To Test:

<!-- Test instructions per dependency update: https://github.com/wordpress-mobile/WordPress-Android/blob/trunk/docs/test_instructions_per_dependency_update.md -->

Test this with both the `stats_traffic_tab` enabled and disabled cases:
1. Open "My Site → Stats"
2. Change granularity to something different from "Day".
1. Tap on the "Today's Stats" card from My Site.
3. Verify that it opens the Day granularity in Stats.

-----

## Regression Notes

1. Potential unintended areas of impact

    - Opening Stats from other entry points.

4. What I did to test those areas of impact (or what existing automated tests I relied on)

    - Tested manually.

5. What automated tests I added (or what prevented me from doing so)

    - Updated current tests.

-----

## PR Submission Checklist:

- [x] I have completed the Regression Notes.
- [x] I have considered adding accessibility improvements for my changes.
- [x] I have considered if this change warrants user-facing release notes and have added them to `RELEASE-NOTES.txt` if necessary.

-----

## Testing Checklist (strike-out the not-applying and unnecessary ones):

- [ ] ~WordPress.com sites and self-hosted Jetpack sites.~
- [ ] ~Portrait and landscape orientations.~
- [ ] ~Light and dark modes.~
- [ ] ~Fonts: Larger, smaller and bold text.~
- [ ] ~High contrast.~
- [ ] ~Talkback.~
- [ ] ~Languages with large words or with letters/accents not frequently used in English.~
- [ ] ~Right-to-left languages. (Even if translation isn’t complete, formatting should still respect the right-to-left layout)~
- [ ] ~Large and small screen sizes. (Tablet and smaller phones)~
- [ ] ~Multi-tasking: Split screen and Pop-up view. (Android 10 or higher)~

Today's Stats card should open the day granularity on stats
### Expected behavior
Today's Stats card should open the TRAFFIC tab with "By day" granularity or DAYS tab (when the `stats_traffic_tab` flag is off).

### Actual behavior
Today's Stats card is opening the INSIGHTS tab.

[todays stats issue.webm](https://github.com/wordpress-mobile/WordPress-Android/assets/2471769/7ab68309-b90e-4a9a-9322-69ff57aa2d2c)

### Steps to reproduce the behavior
1. Log in.
2. Tap the dots button on the "Today's Stats" card.
3. Tap "View stats".

##### Tested on Pixel 9 Pro Emulator, Android 14, JPAndroid 24.4

diff --git a/WordPress/src/main/java/org/wordpress/android/ui/mysite/MySiteFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/mysite/MySiteFragment.kt
index 6f8c47d8c624..da8880893f82 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/mysite/MySiteFragment.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/mysite/MySiteFragment.kt
@@ -654,10 +654,10 @@ class MySiteFragment : Fragment(R.layout.my_site_fragment),
         is SiteNavigationAction.EditScheduledPost ->
             ActivityLauncher.viewCurrentBlogPostsOfType(requireActivity(), action.site, PostListType.SCHEDULED)

-        is SiteNavigationAction.OpenStatsInsights -> ActivityLauncher.viewBlogStatsForTimeframe(
+        is SiteNavigationAction.OpenStatsByDay -> ActivityLauncher.viewBlogStatsForTimeframe(
             requireActivity(),
             action.site,
-            StatsTimeframe.INSIGHTS,
+            StatsTimeframe.DAY,
             StatsLaunchedFrom.TODAY_STATS_CARD
         )

diff --git a/WordPress/src/main/java/org/wordpress/android/ui/mysite/SiteNavigationAction.kt b/WordPress/src/main/java/org/wordpress/android/ui/mysite/SiteNavigationAction.kt
index 698131c54497..18fcc1edcd09 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/mysite/SiteNavigationAction.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/mysite/SiteNavigationAction.kt
@@ -64,7 +64,7 @@ sealed class SiteNavigationAction {
     data class OpenScheduledPosts(val site: SiteModel) : SiteNavigationAction()
     data class EditDraftPost(val site: SiteModel, val postId: Int) : SiteNavigationAction()
     data class EditScheduledPost(val site: SiteModel, val postId: Int) : SiteNavigationAction()
-    data class OpenStatsInsights(val site: SiteModel) : SiteNavigationAction()
+    data class OpenStatsByDay(val site: SiteModel) : SiteNavigationAction()
     data class OpenExternalUrl(val url: String) : SiteNavigationAction()
     data class OpenUrlInWebView(val url: String) : SiteNavigationAction()
     data class OpenDeepLink(val url: String) : SiteNavigationAction()
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/todaysstats/TodaysStatsViewModelSlice.kt b/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/todaysstats/TodaysStatsViewModelSlice.kt
index 41732c261431..068f35d7160b 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/todaysstats/TodaysStatsViewModelSlice.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/mysite/cards/dashboard/todaysstats/TodaysStatsViewModelSlice.kt
@@ -90,7 +90,7 @@ class TodaysStatsViewModelSlice @Inject constructor(
         if (jetpackFeatureRemovalPhaseHelper.shouldShowStaticPage()) {
             _onNavigation.value = Event(SiteNavigationAction.ShowJetpackRemovalStaticPostersView)
         } else {
-            _onNavigation.value = Event(SiteNavigationAction.OpenStatsInsights(selectedSite))
+            _onNavigation.value = Event(SiteNavigationAction.OpenStatsByDay(selectedSite))
         }
     }

diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewModel.kt
index d0e9a5f4a8b5..dc2053d61f74 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewModel.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/StatsViewModel.kt
@@ -196,7 +196,14 @@ class StatsViewModel
                 tapSource = launchedFrom?.value ?: ""
             )

-            initialSection?.let { statsSectionManager.setSelectedSection(it) }
+            initialSection?.let {
+                statsSectionManager.setSelectedSection(it)
+
+                val trafficGranularity = it.toStatsGranularity()
+                if (statsTrafficTabFeatureConfig.isEnabled() && trafficGranularity != null) {
+                    selectedTrafficGranularityManager.setSelectedTrafficGranularity(trafficGranularity)
+                }
+            }
             granularity?.let {
                 if (it != selectedTrafficGranularityManager.getSelectedTrafficGranularity()) {
                     selectedTrafficGranularityManager.setSelectedTrafficGranularity(it)
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/SelectedSectionManager.kt b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/SelectedSectionManager.kt
index 5f5df372abb5..ef835102ca26 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/SelectedSectionManager.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/stats/refresh/utils/SelectedSectionManager.kt
@@ -10,8 +10,6 @@ import org.wordpress.android.fluxc.network.utils.StatsGranularity.MONTHS
 import org.wordpress.android.fluxc.network.utils.StatsGranularity.WEEKS
 import org.wordpress.android.fluxc.network.utils.StatsGranularity.YEARS
 import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection
-import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.INSIGHTS
-import org.wordpress.android.ui.stats.refresh.lists.StatsListViewModel.StatsSection.TRAFFIC
 import org.wordpress.android.util.config.StatsTrafficTabFeatureConfig
 import javax.inject.Inject

@@ -33,9 +31,9 @@ class SelectedSectionManager
         }

     fun getSelectedSection(): StatsSection {
-        val defaultValue = if (statsTrafficTabFeatureConfig.isEnabled()) TRAFFIC else INSIGHTS
+        val defaultValue = if (statsTrafficTabFeatureConfig.isEnabled()) StatsSection.TRAFFIC else StatsSection.INSIGHTS
         val value = sharedPrefs.getString(SELECTED_SECTION_KEY, defaultValue.name)
-        return value?.let { StatsSection.valueOf(value) } ?: INSIGHTS
+        return value?.let { StatsSection.valueOf(value) } ?: StatsSection.INSIGHTS
     }

     fun setSelectedSection(selectedSection: StatsSection) {
@@ -63,15 +61,6 @@ fun StatsSection.toStatsGranularity(): StatsGranularity? {
     }
 }

-fun StatsGranularity.toStatsSection(): StatsSection {
-    return when (this) {
-        DAYS -> StatsSection.DAYS
-        WEEKS -> StatsSection.WEEKS
-        MONTHS -> StatsSection.MONTHS
-        YEARS -> StatsSection.YEARS
-    }
-}
-
 fun StatsGranularity.toNameResource() = when {
     this == DAYS -> R.string.stats_timeframe_by_day
     this == WEEKS -> R.string.stats_timeframe_by_week

diff --git a/WordPress/src/test/java/org/wordpress/android/ui/mysite/cards/dashboard/todaysstats/TodaysStatsViewModelSliceTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/mysite/cards/dashboard/todaysstats/TodaysStatsViewModelSliceTest.kt
index 417d24ae3ef3..44cbebff3a7b 100644
--- a/WordPress/src/test/java/org/wordpress/android/ui/mysite/cards/dashboard/todaysstats/TodaysStatsViewModelSliceTest.kt
+++ b/WordPress/src/test/java/org/wordpress/android/ui/mysite/cards/dashboard/todaysstats/TodaysStatsViewModelSliceTest.kt
@@ -74,7 +74,7 @@ class TodaysStatsViewModelSliceTest : BaseUnitTest() {

             params.onTodaysStatsCardClick()

-            assertThat(navigationActions).containsOnly(SiteNavigationAction.OpenStatsInsights(site))
+            assertThat(navigationActions).containsOnly(SiteNavigationAction.OpenStatsByDay(site))
             verify(cardsTracker).trackCardItemClicked(
                 CardsTracker.Type.STATS.label,
                 CardsTracker.StatsSubtype.TODAYS_STATS.label
@@ -120,7 +120,7 @@ class TodaysStatsViewModelSliceTest : BaseUnitTest() {
             CardsTracker.Type.STATS.label,
             TodaysStatsMenuItemType.VIEW_STATS.label
         )
-        assertThat(navigationActions).containsOnly(SiteNavigationAction.OpenStatsInsights(site))
+        assertThat(navigationActions).containsOnly(SiteNavigationAction.OpenStatsByDay(site))
     }