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 89b16cb43267..37a3dbbe7541 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 @@ -73,6 +73,8 @@ public enum DeletablePrefKey implements PrefKey { READER_ANALYTICS_COUNT_TAGS_TIMESTAMP, + READER_ANALYTICS_COUNT_SITES_TIMESTAMP, + // currently active tab on the main Reader screen when the user is in Reader READER_ACTIVE_TAB, @@ -1172,6 +1174,14 @@ public static void setReaderAnalyticsCountTagsTimestamp(long timestamp) { setLong(DeletablePrefKey.READER_ANALYTICS_COUNT_TAGS_TIMESTAMP, timestamp); } + public static long getReaderAnalyticsCountSitesTimestamp() { + return getLong(DeletablePrefKey.READER_ANALYTICS_COUNT_SITES_TIMESTAMP, -1); + } + + public static void setReaderAnalyticsCountSitesTimestamp(long timestamp) { + setLong(DeletablePrefKey.READER_ANALYTICS_COUNT_SITES_TIMESTAMP, timestamp); + } + public static long getReaderCssUpdatedTimestamp() { return getLong(DeletablePrefKey.READER_CSS_UPDATED_TIMESTAMP, 0); } 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 6052c7a85e7d..feaccdd8ce72 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 @@ -63,6 +63,10 @@ class AppPrefsWrapper @Inject constructor() { get() = AppPrefs.getReaderTagsUpdatedTimestamp() set(timestamp) = AppPrefs.setReaderTagsUpdatedTimestamp(timestamp) + var readerAnalyticsCountTagsTimestamp: Long + get() = AppPrefs.getReaderAnalyticsCountTagsTimestamp() + set(timestamp) = AppPrefs.setReaderAnalyticsCountTagsTimestamp(timestamp) + var readerCssUpdatedTimestamp: Long get() = AppPrefs.getReaderCssUpdatedTimestamp() set(timestamp) = AppPrefs.setReaderCssUpdatedTimestamp(timestamp) 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 2426057c20dc..41e5e1254acf 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 @@ -29,15 +29,18 @@ private ReaderEvents() { public static class FollowedTagsFetched { private final boolean mDidSucceed; private final boolean mDidChange; + private final int mTotalTags; - public FollowedTagsFetched(boolean didSucceed) { + public FollowedTagsFetched(boolean didSucceed, int tagsFollowed) { mDidSucceed = didSucceed; mDidChange = true; + mTotalTags = tagsFollowed; } - public FollowedTagsFetched(boolean didSucceed, boolean didChange) { + public FollowedTagsFetched(boolean didSucceed, int tagsFollowed, boolean didChange) { mDidSucceed = didSucceed; mDidChange = didChange; + mTotalTags = tagsFollowed; } public boolean didSucceed() { @@ -47,6 +50,9 @@ public boolean didSucceed() { public boolean didChange() { return mDidChange; } + public int getTotalTags() { + return mTotalTags; + } } public static class TagAdded { @@ -61,13 +67,19 @@ public String getTagName() { } } - public static class FollowedBlogsChanged { + public static class FollowedBlogsFetched { private final int mTotalSubscriptions; + private final boolean mDidChange; + + public boolean didChange() { + return mDidChange; + } public int getTotalSubscriptions() { return mTotalSubscriptions; } - public FollowedBlogsChanged(int totalSubscriptions) { + public FollowedBlogsFetched(int totalSubscriptions, boolean didChange) { mTotalSubscriptions = totalSubscriptions; + mDidChange = didChange; } } 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 fcad46bae9e5..809ec2bfcaa3 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.FollowedBlogsFetched; import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsFetched; import org.wordpress.android.ui.reader.ReaderEvents.TagAdded; import org.wordpress.android.ui.reader.ReaderTypes.ReaderPostListType; @@ -118,7 +119,6 @@ import org.wordpress.android.ui.reader.subfilter.SubfilterListItem.SiteAll; import org.wordpress.android.ui.reader.tracker.ReaderTracker; import org.wordpress.android.ui.reader.usecases.ReaderSiteFollowUseCase.FollowSiteState.FollowStatusChanged; -import org.wordpress.android.ui.reader.utils.DateProvider; import org.wordpress.android.ui.reader.utils.ReaderUtils; import org.wordpress.android.ui.reader.viewmodels.ReaderModeInfo; import org.wordpress.android.ui.reader.viewmodels.ReaderPostListViewModel; @@ -949,28 +949,18 @@ public void onEventMainThread(FollowedTagsFetched event) { updateCurrentTag(); } } - - // Check last time we've bumped tags followed analytics for this user, - // and bumping again if > 1 hrs - long tagsUpdatedTimestamp = AppPrefs.getReaderAnalyticsCountTagsTimestamp(); - long now = new DateProvider().getCurrentDate().getTime(); - if (now - tagsUpdatedTimestamp > 1000 * 60 * 60) { // 1 hr - ReaderTracker.trackFollowedTagsCount(ReaderTagTable.getFollowedTags().size()); - AppPrefs.setReaderAnalyticsCountTagsTimestamp(now); - } } @SuppressWarnings("unused") @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(ReaderEvents.FollowedBlogsChanged event) { + public void onEventMainThread(FollowedBlogsFetched event) { // refresh posts if user is viewing "Followed Sites" - if (getPostListType() == ReaderPostListType.TAG_FOLLOWED + if (event.didChange() + && getPostListType() == ReaderPostListType.TAG_FOLLOWED && hasCurrentTag() && (getCurrentTag().isFollowedSites() || getCurrentTag().isDefaultInMemoryTag())) { refreshPosts(); } - - ReaderTracker.trackSubscribedSitesCount(event.getTotalSubscriptions()); } @Override 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 3e8914829792..2bf6b1cb6b59 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.FollowedBlogsFetched; import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsFetched; import org.wordpress.android.ui.reader.actions.ReaderActions; import org.wordpress.android.ui.reader.actions.ReaderBlogActions; @@ -211,9 +212,11 @@ public void onEventMainThread(FollowedTagsFetched event) { @SuppressWarnings("unused") @Subscribe(threadMode = ThreadMode.MAIN) - public void onEventMainThread(ReaderEvents.FollowedBlogsChanged event) { - AppLog.d(AppLog.T.READER, "reader subs > followed blogs changed"); - getPageAdapter().refreshBlogFragments(ReaderBlogType.FOLLOWED); + public void onEventMainThread(FollowedBlogsFetched event) { + if (event.didChange()) { + AppLog.d(AppLog.T.READER, "reader subs > followed blogs changed"); + getPageAdapter().refreshBlogFragments(ReaderBlogType.FOLLOWED); + } } private void performUpdate() { 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 8e9ec0895f73..acabc9bc2740 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 @@ -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 FollowedTagsFetched(true)); + EventBus.getDefault().post(new FollowedTagsFetched(true, ReaderTagTable.getFollowedTags().size())); return true; } @@ -130,7 +130,7 @@ public static boolean addTags(@NonNull final List tags, private static boolean saveTagsLocallyOnly(ActionListener actionListener, ReaderTagList newTags) { ReaderTagTable.addOrUpdateTags(newTags); ReaderActions.callActionListener(actionListener, true); - EventBus.getDefault().post(new FollowedTagsFetched(true)); + EventBus.getDefault().post(new FollowedTagsFetched(true, ReaderTagTable.getFollowedTags().size())); return true; } @@ -147,7 +147,7 @@ private static boolean saveTagsLocallyAndRemotely(ActionListener actionListener, if (actionListener != null) { ReaderActions.callActionListener(actionListener, true); } - EventBus.getDefault().post(new FollowedTagsFetched(true)); + EventBus.getDefault().post(new FollowedTagsFetched(true, ReaderTagTable.getFollowedTags().size())); }; 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 FollowedTagsFetched(true)); + EventBus.getDefault().post(new FollowedTagsFetched(true, ReaderTagTable.getFollowedTags().size())); return; } @@ -171,7 +171,7 @@ private static boolean saveTagsLocallyAndRemotely(ActionListener actionListener, if (actionListener != null) { ReaderActions.callActionListener(actionListener, false); } - EventBus.getDefault().post(new FollowedTagsFetched(false)); + EventBus.getDefault().post(new FollowedTagsFetched(false, ReaderTagTable.getFollowedTags().size())); }; ReaderTagTable.addOrUpdateTags(newTags); 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 9f1278a5667c..7f52800a679c 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 @@ -23,7 +23,7 @@ import org.wordpress.android.models.ReaderTagType; 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.FollowedBlogsFetched; import org.wordpress.android.ui.reader.ReaderEvents.FollowedTagsFetched; import org.wordpress.android.ui.reader.ReaderEvents.InterestTagsFetchEnded; import org.wordpress.android.ui.reader.services.ServiceCompletionListener; @@ -193,7 +193,9 @@ public void run() { // broadcast the fact that there are changes didChangeFollowedTags = true; } - EventBus.getDefault().post(new FollowedTagsFetched(true, didChangeFollowedTags)); + EventBus.getDefault().post(new FollowedTagsFetched(true, + ReaderTagTable.getFollowedTags().size(), + didChangeFollowedTags)); AppPrefs.setReaderTagsUpdatedTimestamp(new Date().getTime()); taskCompleted(UpdateTask.TAGS); @@ -327,6 +329,9 @@ public void run() { // but it's better to keep it separate since we aim to remove this check as soon as possible. removeDuplicateBlogs(serverBlogs); + boolean sitesSubscribedChanged = false; + final int totalSites = jsonObject == null ? 0 : jsonObject.optInt("total_subscriptions", 0); + if (!localBlogs.isSameList(serverBlogs)) { // always update the list of followed blogs if there are *any* changes between // server and local (including subscription count, description, etc.) @@ -335,13 +340,12 @@ public void run() { // changed if the server list doesn't have the same blogs as the local list // (ie: a blog has been followed/unfollowed since local was last updated) if (!localBlogs.hasSameBlogs(serverBlogs)) { - final int totalSites = jsonObject == null ? 0 : jsonObject.optInt("total_subscriptions", 0); ReaderPostTable.updateFollowedStatus(); AppLog.i(AppLog.T.READER, "reader blogs service > followed blogs changed"); - EventBus.getDefault().post(new ReaderEvents.FollowedBlogsChanged(totalSites)); + sitesSubscribedChanged = true; } } - + EventBus.getDefault().post(new FollowedBlogsFetched(totalSites, sitesSubscribedChanged)); taskCompleted(UpdateTask.FOLLOWED_BLOGS); } }.start(); 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 a9dd37639a36..5f806bb6ad8b 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 @@ -400,9 +400,11 @@ class SubFilterViewModel @Inject constructor( @Suppress("unused", "UNUSED_PARAMETER") @Subscribe(threadMode = ThreadMode.MAIN) - fun onEventMainThread(event: ReaderEvents.FollowedBlogsChanged) { - AppLog.d(T.READER, "Subfilter bottom sheet > followed blogs changed") - loadSubFilters() + fun onEventMainThread(event: ReaderEvents.FollowedBlogsFetched) { + if(event.didChange()) { + AppLog.d(T.READER, "Subfilter bottom sheet > followed blogs changed") + loadSubFilters() + } } override fun onCleared() { diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/tracker/ReaderTracker.kt b/WordPress/src/main/java/org/wordpress/android/ui/reader/tracker/ReaderTracker.kt index d935b29b57a9..2266d20b391f 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/reader/tracker/ReaderTracker.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/tracker/ReaderTracker.kt @@ -399,6 +399,21 @@ class ReaderTracker @Inject constructor( } } + private fun trackFollowedCount(type: String, numberOfItems: Int) { + val props: MutableMap = HashMap() + props["type"] = type + props["count"] = numberOfItems.toString() + AnalyticsTracker.track(Stat.READER_FOLLOWING_FETCHED, props) + } + + fun trackFollowedTagsCount(numberOfItems: Int) { + trackFollowedCount("tags", numberOfItems) + } + + fun trackSubscribedSitesCount(numberOfItems: Int) { + trackFollowedCount("sites", numberOfItems) + } + /* HELPER */ @JvmOverloads @@ -466,23 +481,6 @@ class ReaderTracker @Inject constructor( AnalyticsTracker.track(stat, properties) } - private fun trackFollowedCount(type: String, numberOfItems: Int) { - val props: MutableMap = HashMap() - props["type"] = type - props["count"] = numberOfItems.toString() - AnalyticsTracker.track(Stat.READER_FOLLOWING_FETCHED, props) - } - - @JvmStatic - fun trackFollowedTagsCount(numberOfItems: Int) { - trackFollowedCount("tags", numberOfItems) - } - - @JvmStatic - fun trackSubscribedSitesCount(numberOfItems: Int) { - trackFollowedCount("sites", numberOfItems) - } - fun isUserProfileSource(source: String): Boolean { return (source == SOURCE_READER_LIKE_LIST_USER_PROFILE || source == SOURCE_NOTIF_LIKE_LIST_USER_PROFILE || 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 4232579bd121..5806d169043a 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 @@ -31,6 +31,7 @@ import org.wordpress.android.ui.jetpackoverlay.JetpackFeatureRemovalOverlayUtil import org.wordpress.android.ui.jetpackoverlay.JetpackOverlayConnectedFeature.READER import org.wordpress.android.ui.mysite.SelectedSiteRepository import org.wordpress.android.ui.mysite.cards.quickstart.QuickStartRepository +import org.wordpress.android.ui.prefs.AppPrefs import org.wordpress.android.ui.prefs.AppPrefsWrapper import org.wordpress.android.ui.quickstart.QuickStartEvent import org.wordpress.android.ui.reader.ReaderEvents @@ -60,6 +61,7 @@ import kotlin.coroutines.CoroutineContext const val UPDATE_TAGS_THRESHOLD = 1000 * 60 * 60 // 1 hr const val TRACK_TAB_CHANGED_THROTTLE = 100L +const val ONE_HOUR_MILLIS = 1000 * 60 * 60 @Suppress("ForbiddenComment") class ReaderViewModel @Inject constructor( @@ -220,6 +222,29 @@ class ReaderViewModel @Inject constructor( @Subscribe(threadMode = MAIN) fun onTagsUpdated(event: ReaderEvents.FollowedTagsFetched) { loadTabs() + // Determine if analytics should be bumped either due to tags changed or time elapsed since last bump + val now = DateProvider().getCurrentDate().time + val shouldBumpAnalytics = event.didChange() + || ( now - appPrefsWrapper.readerAnalyticsCountTagsTimestamp > ONE_HOUR_MILLIS) + + if (shouldBumpAnalytics) { + readerTracker.trackFollowedTagsCount(event.totalTags) + appPrefsWrapper.readerAnalyticsCountTagsTimestamp = now + } + } + + @Suppress("unused", "UNUSED_PARAMETER") + @Subscribe(threadMode = MAIN) + fun onSubscribedSitesUpdated(event: ReaderEvents.FollowedBlogsFetched) { + // Determine if analytics should be bumped either due to sites changed or time elapsed since last bump + val now = DateProvider().getCurrentDate().time + val shouldBumpAnalytics = event.didChange() + || (now - AppPrefs.getReaderAnalyticsCountSitesTimestamp() > ONE_HOUR_MILLIS) + + if (shouldBumpAnalytics) { + readerTracker.trackSubscribedSitesCount(event.totalSubscriptions) + AppPrefs.setReaderAnalyticsCountSitesTimestamp(now) + } } fun onScreenInForeground() { 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 5c0c086000e0..d117e66fd7ba 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 @@ -64,7 +64,7 @@ class FetchFollowedTagsUseCaseTest : BaseUnitTest() { fun `Success returned when FollowedTagsFetched event is posted with success`() = test { // Given whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(true) - val event = FollowedTagsFetched(true) + val event = FollowedTagsFetched(true, 10) whenever(readerUpdateServiceStarterWrapper.startService(contextProvider.getContext(), EnumSet.of(TAGS))) .then { useCase.onFollowedTagsFetched(event) } @@ -79,7 +79,7 @@ class FetchFollowedTagsUseCaseTest : BaseUnitTest() { fun `RemoteRequestFailure returned when FollowedTagsFetched event is posted with failure`() = test { // Given whenever(networkUtilsWrapper.isNetworkAvailable()).thenReturn(true) - val event = FollowedTagsFetched(false) + val event = FollowedTagsFetched(false, 10) whenever(readerUpdateServiceStarterWrapper.startService(contextProvider.getContext(), EnumSet.of(TAGS))) .then { useCase.onFollowedTagsFetched(event) } 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 3a87558edee4..3a761b2108b5 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 @@ -251,7 +251,8 @@ class ReaderDiscoverDataProviderTest : BaseUnitTest() { // Act dataProvider.onFollowedTagsFetched( FollowedTagsFetched( - true + true, + 10 ) ) // Assert