Repository: wordpress-mobile/WordPress-Android (language: kotlin)

Issue:
[Reader IA][Bug][0 tags/blogs] Infinite loading indicator on Subscription feed after subscribing to tags
### Expected behavior
After going to "Suggested tags" flow inside the Tag filter bottom and returning to the Subscriptions feed it should still show the empty state (as there are still 0 blogs being followed) and not show a loading indicator indefinitely.

### Actual behavior
After going to "Suggested tags" flow inside the Tag filter bottom and returning to the Subscriptions feed it shows a loading indicator indefinitely on top of a blank feed.


https://github.com/wordpress-mobile/WordPress-Android/assets/5091503/5e88ec3f-7199-49e1-a5e8-eafcadecf4c0

### Steps to reproduce the behavior
Make sure to unsubscribe from all tags and blogs.

1. Install and log into Jetpack on a `feature/reader-ia` branch build
2. Go to reader
3. Go to the Subscriptions feed
4. Tap "0 tags" filter pill
5. Tap "Suggested tags"
6. Choose zero or more tags and tap "Done"/back
7. **Verify** it goes back to Subscription Feed in an infinite loading state
[Reader IA][Bug][0 blogs/tags] Subscription feed tries refreshing when tapping filter pill
### Expected behavior
When tapping a filter pill (either blogs or tags) the Subscription post feed should not try to refresh, unless the fetch for the filters updates the subscribed blog list and it now has at least 1 blog.

### Actual behavior
When tapping a filter pill (either blogs or tags) the Subscription post feed always tries to refresh.

### Steps to reproduce the behavior
Make sure to unsubscribe from all tags and blogs.

1. Install and log into Jetpack on a `feature/reader-ia` branch build
2. Go to reader
3. Go to the Subscriptions feed
4. Tap either the "0 blogs" or "0 tags" filter pill
5. **Verify** the feed tries to refresh (show the refresh indicator)



Discussion hints:

Pull request: [Reader][0 blogs/0 tags] Fix Subscription feed infinite loading and fetch when tapping filters
Fixes #20009 
Fixes #20010 

The biggest change in this PR is fixing the logic inside `ReaderUpdateLogic` to avoid unnecessary DB writes which were happening always, even when the server tag list was the same as the local tag list, which in turn made the `FollowTagsChanged` stop being triggered every single time a fetch was done.

Fixing that issue made the `FollowTagsChanged` event only be triggered when we, in fact, had changes in the local tag DB, which solved the issues referenced above BUT broke a lot of other things, since much of the existing code listening to that event was relying on `FollowTagsChanged` being triggered at the end of all tag fetching tasks.

To solve that I renamed the `FollowTagsChanged` to `FollowTagsFetched` and made it trigger in the same situation as it was before (regardless of changes being made to the local DB), added a new field `didChange` to propagate the information if a change was done locally or not, and updated the logic in `ReaderPostListFragment` event listener that caused the 2 bugs above to happen, by guarding with the specific conditions in which we really want fetching to happen

-----

## To Test:

Before running each test scenarios below make sure you have 0 blogs and 0 tags followed.

### Infinite loading after subscribing to tags
1. Install and log into Jetpack on a `feature/reader-ia` branch build
2. Go to reader
3. Go to the Subscriptions feed
4. Tap "0 tags" filter pill
5. Tap "Suggested tags"
6. Choose zero or more tags and tap "Done"/back
7. **Verify** it goes back to Subscription Feed and the page has no infinite loading indicator

### Tapping the blog/tag filter pills causes the empty list to refresh
1. Install and log into Jetpack on a `feature/reader-ia` branch build
2. Go to reader
3. Go to the Subscriptions feed
4. Tap either the "0 blogs" or "0 tags" filter pill
5. **Verify** the feed does not try to refresh since there are no subscribed blogs

-----

## Regression Notes

1. Potential unintended areas of impact
    - Normal scenarios of reader (with tags/blogs subscriptions)

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)
    - Updated existing unit 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:

- [ ] 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)


Test command: ./gradlew :WordPress:testWordpressVanillaDebugUnitTest --tests "org.wordpress.android.ui.reader.repository.ReaderDiscoverDataProviderTest" --tests "org.wordpress.android.ui.reader.repository.FetchFollowedTagsUseCaseTest" --tests "org.wordpress.android.ui.reader.viewmodels.ReaderViewModelTest"

Fix patch:
diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderTagTable.java b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderTagTable.java
index 977f7eaf0f2e..7c7530756b12 100644
--- a/WordPress/src/main/java/org/wordpress/android/datasets/ReaderTagTable.java
+++ b/WordPress/src/main/java/org/wordpress/android/datasets/ReaderTagTable.java
@@ -232,6 +232,10 @@ public static ReaderTagList getBookmarkTags() {
         return getTagsOfType(ReaderTagType.BOOKMARKED);
     }
 
+    public static ReaderTagList getDiscoverPostCardsTags() {
+        return getTagsOfType(ReaderTagType.DISCOVER_POST_CARDS);
+    }
+
     private static ReaderTagList getTagsOfType(ReaderTagType tagType) {
         String[] args = {Integer.toString(tagType.toInt())};
         Cursor c = ReaderDatabase.getReadableDb()
diff --git a/WordPress/src/main/java/org/wordpress/android/models/ReaderTagList.java b/WordPress/src/main/java/org/wordpress/android/models/ReaderTagList.java
index 6a9633c44441..12da31783833 100644
--- a/WordPress/src/main/java/org/wordpress/android/models/ReaderTagList.java
+++ b/WordPress/src/main/java/org/wordpress/android/models/ReaderTagList.java
@@ -44,6 +44,8 @@ public boolean isSameList(ReaderTagList otherList) {
                 return false;
             } else if (!otherTag.getTagTitle().equals(this.get(i).getTagTitle())) {
                 return false;
+            } else if (!otherTag.getTagDisplayName().equals(this.get(i).getTagDisplayName())) {
+                return false;
             }
         }
 
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderEvents.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderEvents.java
index e107db26f932..de72a22e2b40 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderEvents.java
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderEvents.java
@@ -26,16 +26,27 @@ private ReaderEvents() {
         throw new AssertionError();
     }
 
-    public static class FollowedTagsChanged {
+    public static class FollowedTagsFetched {
         private final boolean mDidSucceed;
+        private final boolean mDidChange;
 
-        public FollowedTagsChanged(boolean didSucceed) {
+        public FollowedTagsFetched(boolean didSucceed) {
             mDidSucceed = didSucceed;
+            mDidChange = true;
+        }
+
+        public FollowedTagsFetched(boolean didSucceed, boolean didChange) {
+            mDidSucceed = didSucceed;
+            mDidChange = didChange;
         }
 
         public boolean didSucceed() {
             return mDidSucceed;
         }
+
+        public boolean didChange() {
+            return mDidChange;
+        }
     }
 
     public static class TagAdded {
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java
index 2da410a95ab6..287204bb16d1 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java
@@ -84,6 +84,7 @@
 import org.wordpress.android.ui.mysite.jetpackbadge.JetpackPoweredBottomSheetFragment;
 import org.wordpress.android.ui.pages.SnackbarMessageHolder;
 import org.wordpress.android.ui.prefs.AppPrefs;
+import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsFetched;
 import org.wordpress.android.ui.reader.ReaderEvents.TagAdded;
 import org.wordpress.android.ui.reader.ReaderTypes.ReaderPostListType;
 import org.wordpress.android.ui.reader.actions.ReaderActions;
@@ -934,14 +935,16 @@ private void resetPostAdapter(ReaderPostListType postListType) {
 
     @SuppressWarnings("unused")
     @Subscribe(threadMode = ThreadMode.MAIN)
-    public void onEventMainThread(ReaderEvents.FollowedTagsChanged event) {
+    public void onEventMainThread(FollowedTagsFetched event) {
         if (getPostListType() == ReaderPostListType.TAG_FOLLOWED) {
-            // reload the tag filter since tags have changed
-            reloadTags();
+            if (event.didChange()) {
+                // reload the tag filter since tags have changed or we just opened the fragment
+                reloadTags();
+            }
 
             // update the current tag if the list fragment is empty - this will happen if
             // the tag table was previously empty (ie: first run)
-            if (isPostAdapterEmpty()) {
+            if (isPostAdapterEmpty() && (ReaderBlogTable.hasFollowedBlogs() || !mHasUpdatedPosts)) {
                 updateCurrentTag();
             }
         }
@@ -1724,9 +1727,6 @@ private void setEmptyTitleDescriptionAndButton(boolean requestFailed) {
         // Ensure the default image is reset for empty views before applying logic
         mActionableEmptyView.image.setImageResource(R.drawable.illustration_reader_empty);
 
-        // TODO thomashortadev
-        //  try to quickly hack some way of making the button black
-
         if (shouldShowEmptyViewForSelfHostedCta()) {
             setEmptyTitleAndDescriptionForSelfHostedCta();
             return;
@@ -1940,7 +1940,9 @@ private void showBookmarksSavedLocallyDialog(ShowBookmarkedSavedOnlyLocallyDialo
                 .setCancelable(false)
                 .create();
         mBookmarksSavedLocallyDialog.show();
-    }    /*
+    }
+
+    /*
      * called by post adapter when data has been loaded
      */
     private final ReaderInterfaces.DataLoadedListener mDataLoadedListener = new ReaderInterfaces.DataLoadedListener() {
@@ -2333,7 +2335,7 @@ public void run() {
                             mActionableEmptyView.button.setVisibility(View.GONE);
                             mActionableEmptyView.subtitle.setVisibility(View.GONE);
                             showEmptyView();
-                        } else {
+                        } else if (!isPostAdapterEmpty()) {
                             hideEmptyView();
                         }
                     });
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderSubsActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderSubsActivity.java
index 955a08936ce5..3e8914829792 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderSubsActivity.java
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderSubsActivity.java
@@ -41,6 +41,7 @@
 import org.wordpress.android.ui.LocaleAwareActivity;
 import org.wordpress.android.ui.RequestCodes;
 import org.wordpress.android.ui.prefs.AppPrefs;
+import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsFetched;
 import org.wordpress.android.ui.reader.actions.ReaderActions;
 import org.wordpress.android.ui.reader.actions.ReaderBlogActions;
 import org.wordpress.android.ui.reader.actions.ReaderTagActions;
@@ -203,7 +204,7 @@ protected void onResume() {
 
     @SuppressWarnings("unused")
     @Subscribe(threadMode = ThreadMode.MAIN)
-    public void onEventMainThread(ReaderEvents.FollowedTagsChanged event) {
+    public void onEventMainThread(FollowedTagsFetched event) {
         AppLog.d(AppLog.T.READER, "reader subs > followed tags changed");
         getPageAdapter().refreshFollowedTagFragment();
     }
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/actions/ReaderTagActions.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/actions/ReaderTagActions.java
index 9577553148fa..8e9ec0895f73 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/reader/actions/ReaderTagActions.java
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/actions/ReaderTagActions.java
@@ -13,7 +13,7 @@
 import org.wordpress.android.models.ReaderTagList;
 import org.wordpress.android.models.ReaderTagType;
 import org.wordpress.android.ui.reader.ReaderConstants;
-import org.wordpress.android.ui.reader.ReaderEvents;
+import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsFetched;
 import org.wordpress.android.ui.reader.actions.ReaderActions.ActionListener;
 import org.wordpress.android.ui.reader.utils.ReaderUtils;
 import org.wordpress.android.util.AppLog;
@@ -51,7 +51,7 @@ public static boolean deleteTag(final ReaderTag tag,
     private static boolean deleteTagsLocallyOnly(ActionListener actionListener, ReaderTag tag) {
         ReaderTagTable.deleteTag(tag);
         ReaderActions.callActionListener(actionListener, true);
-        EventBus.getDefault().post(new ReaderEvents.FollowedTagsChanged(true));
+        EventBus.getDefault().post(new FollowedTagsFetched(true));
 
         return true;
     }
@@ -130,7 +130,7 @@ public static boolean addTags(@NonNull final List<ReaderTag> tags,
     private static boolean saveTagsLocallyOnly(ActionListener actionListener, ReaderTagList newTags) {
         ReaderTagTable.addOrUpdateTags(newTags);
         ReaderActions.callActionListener(actionListener, true);
-        EventBus.getDefault().post(new ReaderEvents.FollowedTagsChanged(true));
+        EventBus.getDefault().post(new FollowedTagsFetched(true));
 
         return true;
     }
@@ -147,7 +147,7 @@ private static boolean saveTagsLocallyAndRemotely(ActionListener actionListener,
             if (actionListener != null) {
                 ReaderActions.callActionListener(actionListener, true);
             }
-            EventBus.getDefault().post(new ReaderEvents.FollowedTagsChanged(true));
+            EventBus.getDefault().post(new FollowedTagsFetched(true));
         };
 
         RestRequest.ErrorListener errorListener = volleyError -> {
@@ -159,7 +159,7 @@ private static boolean saveTagsLocallyAndRemotely(ActionListener actionListener,
                 if (actionListener != null) {
                     ReaderActions.callActionListener(actionListener, true);
                 }
-                EventBus.getDefault().post(new ReaderEvents.FollowedTagsChanged(true));
+                EventBus.getDefault().post(new FollowedTagsFetched(true));
                 return;
             }
 
@@ -171,7 +171,7 @@ private static boolean saveTagsLocallyAndRemotely(ActionListener actionListener,
             if (actionListener != null) {
                 ReaderActions.callActionListener(actionListener, false);
             }
-            EventBus.getDefault().post(new ReaderEvents.FollowedTagsChanged(false));
+            EventBus.getDefault().post(new FollowedTagsFetched(false));
         };
 
         ReaderTagTable.addOrUpdateTags(newTags);
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/repository/ReaderDiscoverDataProvider.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/repository/ReaderDiscoverDataProvider.kt
index a1a20185e26d..27b8cb35b031 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/reader/repository/ReaderDiscoverDataProvider.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/repository/ReaderDiscoverDataProvider.kt
@@ -14,7 +14,7 @@ import org.wordpress.android.models.discover.ReaderDiscoverCards
 import org.wordpress.android.modules.IO_THREAD
 import org.wordpress.android.modules.UI_THREAD
 import org.wordpress.android.ui.reader.ReaderEvents.FetchDiscoverCardsEnded
-import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsChanged
+import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsFetched
 import org.wordpress.android.ui.reader.actions.ReaderActions.UpdateResult.CHANGED
 import org.wordpress.android.ui.reader.actions.ReaderActions.UpdateResult.FAILED
 import org.wordpress.android.ui.reader.actions.ReaderActions.UpdateResult.HAS_NEW
@@ -211,7 +211,7 @@ class ReaderDiscoverDataProvider @Inject constructor(
 
     @Suppress("unused", "UNUSED_PARAMETER")
     @Subscribe(threadMode = BACKGROUND)
-    fun onFollowedTagsChanged(event: FollowedTagsChanged) {
+    fun onFollowedTagsFetched(event: FollowedTagsFetched) {
         launch {
             refreshCards()
         }
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/repository/usecases/tags/FetchFollowedTagsUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/repository/usecases/tags/FetchFollowedTagsUseCase.kt
index 3afd6a0d2cf2..1d109666337d 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/reader/repository/usecases/tags/FetchFollowedTagsUseCase.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/repository/usecases/tags/FetchFollowedTagsUseCase.kt
@@ -2,7 +2,7 @@ package org.wordpress.android.ui.reader.repository.usecases.tags
 
 import org.greenrobot.eventbus.Subscribe
 import org.greenrobot.eventbus.ThreadMode
-import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsChanged
+import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsFetched
 import org.wordpress.android.ui.reader.repository.ReaderRepositoryCommunication
 import org.wordpress.android.ui.reader.repository.ReaderRepositoryCommunication.Error.NetworkUnavailable
 import org.wordpress.android.ui.reader.repository.ReaderRepositoryCommunication.Error.RemoteRequestFailure
@@ -48,7 +48,7 @@ class FetchFollowedTagsUseCase @Inject constructor(
 
     @Suppress("unused")
     @Subscribe(threadMode = ThreadMode.BACKGROUND)
-    fun onFollowedTagsChanged(event: FollowedTagsChanged) {
+    fun onFollowedTagsFetched(event: FollowedTagsFetched) {
         val result = if (event.didSucceed()) {
             Success
         } else {
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/repository/usecases/tags/FollowInterestTagsUseCase.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/repository/usecases/tags/FollowInterestTagsUseCase.kt
index 3002e258d450..8e171e262261 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/reader/repository/usecases/tags/FollowInterestTagsUseCase.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/repository/usecases/tags/FollowInterestTagsUseCase.kt
@@ -4,7 +4,7 @@ import org.greenrobot.eventbus.Subscribe
 import org.greenrobot.eventbus.ThreadMode
 import org.wordpress.android.fluxc.store.AccountStore
 import org.wordpress.android.models.ReaderTag
-import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsChanged
+import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsFetched
 import org.wordpress.android.ui.reader.actions.ReaderTagActions
 import org.wordpress.android.ui.reader.repository.ReaderRepositoryCommunication
 import org.wordpress.android.ui.reader.repository.ReaderRepositoryCommunication.Error.NetworkUnavailable
@@ -43,7 +43,7 @@ class FollowInterestTagsUseCase @Inject constructor(
 
     @Suppress("unused")
     @Subscribe(threadMode = ThreadMode.BACKGROUND)
-    fun onFollowedTagsChanged(event: FollowedTagsChanged) {
+    fun onFollowedTagsFetched(event: FollowedTagsFetched) {
         val result = if (event.didSucceed()) {
             Success
         } else {
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/services/update/ReaderUpdateLogic.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/services/update/ReaderUpdateLogic.java
index cde09194380f..e743d7f52bfa 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/reader/services/update/ReaderUpdateLogic.java
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/services/update/ReaderUpdateLogic.java
@@ -24,6 +24,7 @@
 import org.wordpress.android.ui.prefs.AppPrefs;
 import org.wordpress.android.ui.reader.ReaderConstants;
 import org.wordpress.android.ui.reader.ReaderEvents;
+import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsFetched;
 import org.wordpress.android.ui.reader.ReaderEvents.InterestTagsFetchEnded;
 import org.wordpress.android.ui.reader.services.ServiceCompletionListener;
 import org.wordpress.android.util.AppLog;
@@ -122,24 +123,21 @@ public void onErrorResponse(VolleyError volleyError) {
                             .get("read/menu", params, null, listener, errorListener);
     }
 
-    private boolean displayNameUpdateWasNeeded(ReaderTagList serverTopics) {
-        boolean updateDone = false;
-
+    /**
+     * Update the display names of the default tags (such as Subscribed and Discover) in the serverTopics list.
+     *
+     * @param serverTopics The list of default tags.
+     */
+    private void updateDisplayNamesIfNeeded(@NonNull ReaderTagList serverTopics) {
         for (ReaderTag tag : serverTopics) {
-            String tagNameBefore = tag.getTagDisplayName();
             if (tag.isFollowedSites()) {
                 tag.setTagDisplayName(mContext.getString(R.string.reader_subscribed_display_name));
-                if (!tagNameBefore.equals(tag.getTagDisplayName())) updateDone = true;
             } else if (tag.isDiscover()) {
                 tag.setTagDisplayName(mContext.getString(R.string.reader_discover_display_name));
-                if (!tagNameBefore.equals(tag.getTagDisplayName())) updateDone = true;
             } else if (tag.isPostsILike()) {
                 tag.setTagDisplayName(mContext.getString(R.string.reader_my_likes_display_name));
-                if (!tagNameBefore.equals(tag.getTagDisplayName())) updateDone = true;
             }
         }
-
-        return updateDone;
     }
 
     private void handleUpdateTagsResponse(final JSONObject jsonObject) {
@@ -151,7 +149,7 @@ public void run() {
                 ReaderTagList serverTopics = new ReaderTagList();
                 serverTopics.addAll(parseTags(jsonObject, "default", ReaderTagType.DEFAULT));
 
-                boolean displayNameUpdateWasNeeded = displayNameUpdateWasNeeded(serverTopics);
+                updateDisplayNamesIfNeeded(serverTopics);
 
                 serverTopics.addAll(parseTags(jsonObject, "subscribed", ReaderTagType.FOLLOWED));
 
@@ -176,13 +174,11 @@ public void run() {
                 localTopics.addAll(ReaderTagTable.getFollowedTags());
                 localTopics.addAll(ReaderTagTable.getBookmarkTags());
                 localTopics.addAll(ReaderTagTable.getCustomListTags());
+                localTopics.addAll(ReaderTagTable.getDiscoverPostCardsTags());
 
-                if (
-                        !localTopics.isSameList(serverTopics)
-                        || displayNameUpdateWasNeeded
-                ) {
-                    AppLog.d(AppLog.T.READER, "reader service > followed topics changed "
-                                              + "updatedDisplayNames [" + displayNameUpdateWasNeeded + "]");
+                boolean didChangeFollowedTags = false;
+                if (!localTopics.isSameList(serverTopics)) {
+                    AppLog.d(AppLog.T.READER, "reader service > followed topics changed");
 
                     if (!mAccountStore.hasAccessToken()) {
                         // Do not delete locally saved tags for logged out user
@@ -195,8 +191,9 @@ public void run() {
                         ReaderTagTable.replaceTags(serverTopics);
                     }
                     // broadcast the fact that there are changes
-                    EventBus.getDefault().post(new ReaderEvents.FollowedTagsChanged(true));
+                    didChangeFollowedTags = true;
                 }
+                EventBus.getDefault().post(new FollowedTagsFetched(true, didChangeFollowedTags));
                 AppPrefs.setReaderTagsUpdatedTimestamp(new Date().getTime());
 
                 taskCompleted(UpdateTask.TAGS);
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/subfilter/SubFilterViewModel.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/subfilter/SubFilterViewModel.kt
index e331ecaeb231..a9dd37639a36 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/reader/subfilter/SubFilterViewModel.kt
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/subfilter/SubFilterViewModel.kt
@@ -393,7 +393,7 @@ class SubFilterViewModel @Inject constructor(
 
     @Suppress("unused", "UNUSED_PARAMETER")
     @Subscribe(threadMode = ThreadMode.MAIN)
-    fun onEventMainThread(event: ReaderEvents.FollowedTagsChanged) {
+    fun onEventMainThread(event: ReaderEvents.FollowedTagsFetched) {
         AppLog.d(T.READER, "Subfilter bottom sheet > followed tags changed")
         loadSubFilters()
     }
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 a6e26e3f648a..0e13b2f17e0b 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
@@ -135,7 +135,8 @@ class ReaderViewModel @Inject constructor(
 //        _showJetpackPoweredBottomSheet.value = Event(true)
     }
 
-    private fun loadTabs(savedInstanceState: Bundle? = null) {
+    @JvmOverloads
+    fun loadTabs(savedInstanceState: Bundle? = null) {
         launch {
             val tagList = loadReaderTabsUseCase.loadTabs()
             if (tagList.isNotEmpty() && readerTagsList != tagList) {
@@ -215,7 +216,7 @@ class ReaderViewModel @Inject constructor(
 
     @Suppress("unused", "UNUSED_PARAMETER")
     @Subscribe(threadMode = MAIN)
-    fun onTagsUpdated(event: ReaderEvents.FollowedTagsChanged) {
+    fun onTagsUpdated(event: ReaderEvents.FollowedTagsFetched) {
         loadTabs()
     }
 


Test patch:
diff --git a/WordPress/src/test/java/org/wordpress/android/ui/reader/repository/FetchFollowedTagsUseCaseTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/reader/repository/FetchFollowedTagsUseCaseTest.kt
index a581bc43584f..5c0c086000e0 100644
--- a/WordPress/src/test/java/org/wordpress/android/ui/reader/repository/FetchFollowedTagsUseCaseTest.kt
+++ b/WordPress/src/test/java/org/wordpress/android/ui/reader/repository/FetchFollowedTagsUseCaseTest.kt
@@ -9,7 +9,7 @@ import org.mockito.Mock
 import org.mockito.junit.MockitoJUnitRunner
 import org.mockito.kotlin.whenever
 import org.wordpress.android.BaseUnitTest
-import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsChanged
+import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsFetched
 import org.wordpress.android.ui.reader.repository.ReaderRepositoryCommunication.Error.NetworkUnavailable
 import org.wordpress.android.ui.reader.repository.ReaderRepositoryCommunication.Error.RemoteRequestFailure
 import org.wordpress.android.ui.reader.repository.ReaderRepositoryCommunication.Success
@@ -61,12 +61,12 @@ class FetchFollowedTagsUseCaseTest : BaseUnitTest() {
     }
 
     @Test
-    fun `Success returned when FollowedTagsChanged event is posted with true`() = test {
+    fun `Success returned when FollowedTagsFetched event is posted with success`() = test {
         // Given
         whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(true)
-        val event = FollowedTagsChanged(true)
+        val event = FollowedTagsFetched(true)
         whenever(readerUpdateServiceStarterWrapper.startService(contextProvider.getContext(), EnumSet.of(TAGS)))
-            .then { useCase.onFollowedTagsChanged(event) }
+            .then { useCase.onFollowedTagsFetched(event) }
 
         // When
         val result = useCase.fetch()
@@ -76,12 +76,12 @@ class FetchFollowedTagsUseCaseTest : BaseUnitTest() {
     }
 
     @Test
-    fun `RemoteRequestFailure returned when FollowedTagsChanged event is posted with false`() = test {
+    fun `RemoteRequestFailure returned when FollowedTagsFetched event is posted with failure`() = test {
         // Given
         whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(true)
-        val event = FollowedTagsChanged(false)
+        val event = FollowedTagsFetched(false)
         whenever(readerUpdateServiceStarterWrapper.startService(contextProvider.getContext(), EnumSet.of(TAGS)))
-            .then { useCase.onFollowedTagsChanged(event) }
+            .then { useCase.onFollowedTagsFetched(event) }
 
         // When
         val result = useCase.fetch()
diff --git a/WordPress/src/test/java/org/wordpress/android/ui/reader/repository/ReaderDiscoverDataProviderTest.kt b/WordPress/src/test/java/org/wordpress/android/ui/reader/repository/ReaderDiscoverDataProviderTest.kt
index 18f0d5704887..3a87558edee4 100644
--- a/WordPress/src/test/java/org/wordpress/android/ui/reader/repository/ReaderDiscoverDataProviderTest.kt
+++ b/WordPress/src/test/java/org/wordpress/android/ui/reader/repository/ReaderDiscoverDataProviderTest.kt
@@ -16,7 +16,7 @@ import org.wordpress.android.models.ReaderPost
 import org.wordpress.android.models.discover.ReaderDiscoverCard.ReaderPostCard
 import org.wordpress.android.models.discover.ReaderDiscoverCards
 import org.wordpress.android.ui.reader.ReaderEvents.FetchDiscoverCardsEnded
-import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsChanged
+import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsFetched
 import org.wordpress.android.ui.reader.actions.ReaderActions.UpdateResult.FAILED
 import org.wordpress.android.ui.reader.actions.ReaderActions.UpdateResult.HAS_NEW
 import org.wordpress.android.ui.reader.actions.ReaderActions.UpdateResult.UNCHANGED
@@ -249,7 +249,11 @@ class ReaderDiscoverDataProviderTest : BaseUnitTest() {
     @Test
     fun `when followed tags change the discover feed gets refreshed`() = test {
         // Act
-        dataProvider.onFollowedTagsChanged(FollowedTagsChanged(true))
+        dataProvider.onFollowedTagsFetched(
+            FollowedTagsFetched(
+                true
+            )
+        )
         // Assert
         verify(fetchDiscoverCardsUseCase).fetch(REQUEST_FIRST_PAGE)
     }
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 29780c984015..2f437f24465c 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
@@ -177,7 +177,7 @@ class ReaderViewModelTest : BaseUnitTest() {
     }
 
     @Test
-    fun `Tags are reloaded when FollowedTagsChanged event is received`() = testWithNonEmptyTags {
+    fun `Tags are reloaded when FollowedTagsFetched event is received`() = testWithNonEmptyTags {
         // Arrange
         var state: ReaderUiState? = null
         viewModel.uiState.observeForever {