Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reader: Update Reader fetch followed sites to fetch all sites #22842

Merged
merged 3 commits into from
Mar 29, 2024

Conversation

wargcm
Copy link
Contributor

@wargcm wargcm commented Mar 15, 2024

Fixes #15651
WordPressKit PR: wordpress-mobile/WordPressKit-iOS#753

Description

Previously, the API call was only returning the first page of a user's followed sites. This change adds support for a page parameter and uses that to fetch all the pages at the same time.

Testing

I found the easiest way to test it is by reducing the page size and adding print statements to the new function when it fetches pages. You can copy this code block to make it easier:

Test code
    @objc func fetchAllFollowedSites(success: @escaping () -> Void, failure: @escaping (Error?) -> Void) {
        let service = ReaderTopicServiceRemote(wordPressComRestApi: apiRequest())
        let pageSize: UInt = 5

        service.fetchFollowedSites(forPage: 1, number: pageSize) { totalSites, sites in
            guard let totalSites, let sites else {
                failure(nil)
                return
            }
            let totalPages = Int(ceil(Double(totalSites.intValue) / Double(pageSize)))
            WPAnalytics.subscriptionCount = totalSites.intValue
            print("🟣 fetchAllFollowedSites - Total pages \(totalPages)")

            guard totalPages > 1 else {
                print("🟣 fetchAllFollowedSites - Merging \(sites.count) sites")
                self.mergeFollowedSites(sites, withSuccess: success)
                return
            }

            Task {
                print("🟣 fetchAllFollowedSites - Fetching additional pages")
                await withTaskGroup(of: Result<[RemoteReaderSiteInfo], Error>.self) { taskGroup in
                    for page in 2...totalPages {
                        taskGroup.addTask {
                            return await self.fetchFollowedSites(service: service, page: UInt(page), number: pageSize)
                        }
                    }
                    var allSites = sites
                    for await result in taskGroup {
                        if case .success(let sites) = result {
                            allSites.append(contentsOf: sites)
                        }
                    }
                    print("🟣 fetchAllFollowedSites - Merging \(sites.count) sites")
                    self.mergeFollowedSites(allSites, withSuccess: success)
                }
            }
        } failure: { error in
            failure(error)
        }
    }

    private func fetchFollowedSites(service: ReaderTopicServiceRemote, page: UInt, number: UInt) async -> Result<[RemoteReaderSiteInfo], Error> {
        return await withCheckedContinuation { continuation in
            service.fetchFollowedSites(forPage: page, number: number) { _, sites in
                print("🟣 fetchFollowedSites - finished fetching page \(page)")
                continuation.resume(returning: .success(sites ?? []))
            } failure: { error in
                DDLogError("Error fetching page \(page) for followed sites: \(String(describing: error))")
                continuation.resume(returning: .failure(error ?? FollowedSitesError.unknown))
            }
        }
    }

To test:

  • Login to Jetpack
  • Navigate to the dashboard or launch the app to it
  • 🔎 Verify existing start up fetch site calls fetch all your sites
  • Navigate to the Subscriptions feed in the Reader
  • Tap on the Blogs chip
  • Tap on Edit
  • 🔎 Verify the fetch call fetches all of your sites

Regression Notes

  1. Potential unintended areas of impact
    Should be 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)
    N/A

PR submission checklist:

  • I have completed the Regression Notes.
  • I have considered adding unit tests for my changes.
  • I have considered adding accessibility improvements for my changes.
  • 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.
  • VoiceOver.
  • 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)
  • iPhone and iPad.
  • Multi-tasking: Split view and Slide over. (iPad)

@wargcm wargcm requested a review from dvdchr March 15, 2024 23:33
@wargcm wargcm self-assigned this Mar 15, 2024
@dangermattic
Copy link
Collaborator

dangermattic commented Mar 15, 2024

1 Warning
⚠️ PR is not assigned to a milestone.

Generated by 🚫 Danger

@wpmobilebot
Copy link
Contributor

wpmobilebot commented Mar 15, 2024

WordPress Alpha📲 You can test the changes from this Pull Request in WordPress Alpha by scanning the QR code below to install the corresponding build.
App NameWordPress Alpha WordPress Alpha
ConfigurationRelease-Alpha
Build Numberpr22842-259c480
Version24.5
Bundle IDorg.wordpress.alpha
Commit259c480
App Center BuildWPiOS - One-Offs #9315
Automatticians: You can use our internal self-serve MC tool to give yourself access to App Center if needed.

@wpmobilebot
Copy link
Contributor

wpmobilebot commented Mar 15, 2024

Jetpack Alpha📲 You can test the changes from this Pull Request in Jetpack Alpha by scanning the QR code below to install the corresponding build.
App NameJetpack Alpha Jetpack Alpha
ConfigurationRelease-Alpha
Build Numberpr22842-259c480
Version24.5
Bundle IDcom.jetpack.alpha
Commit259c480
App Center Buildjetpack-installable-builds #8359
Automatticians: You can use our internal self-serve MC tool to give yourself access to App Center if needed.

@daniloercoli
Copy link
Contributor

Hey @wargcm 👋 - I installed this PR by updating from an older one and then navigated to the Reader. As expected, the Subscriptions feed was already selected, since i was already in that feed in the old version of the app. However, despite waiting, the Site pill did not update. Attempting to pull to refresh did nothing. Even force closing the app and restarting it did not resolve the issue.
I had to return to the Discovery feed and then go back to Subscriptions to get the pill updated.

@daniloercoli
Copy link
Contributor

On my test account (the one I've shared internally), a couple of sites are not properly displayed in the site selector (see the picture below). When I select one of those sites, I get the "No posts" screen.

Screenshot 2024-03-16 at 11 41 38

I believe the issue involves sites that have an empty title, but i'm not completely sure of that, since when i select them i get the No posts available.
Screenshot 2024-03-16 at 11 42 39

@dvdchr
Copy link
Contributor

dvdchr commented Mar 18, 2024

Thank you for the test code! I tested it several times and found it works quite reliably. 👏

I modified the test prints a bit so that it prints out the amount of allSites at line 41:

print("🟣 fetchAllFollowedSites - Merging \(allSites.count) sites")

I saw 2 missing blogs; the UI shows 107 but the API returns 109. Perhaps they're P2s or private sites? 🤔

Screenshot 2024-03-19 at 03 19 58

Comment on lines 34 to 42
if case .success(let sites) = result {
allSites.append(contentsOf: sites)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm wondering what we should do if errors occur within 2...totalPages. Currently, the errors are ignored, and this may lead to missing sites from the followed blogs list despite the successful result. But I'm not sure myself how we should address this without making it overly complicated... 😅

Some ideas: we could store the failed page numbers to retry. But in case of network errors, it could very well throw the user into a loop of multi-requests, especially considering that fetchAllFollowedSites are getting called multiple times after the app launches.

Anyways, it's still better than just fetching the first page! 😄

Copy link
Contributor

@daniloercoli daniloercoli Mar 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On Android, we're clearing the local sites list and replacing it with new sites fetched from the remote server. To keep the logic straightforward in this initial iteration, we've assumed that a network calls chain is successful only if all paged network calls are completed successfully. At the conclusion of the last call, we consider it a success, store the results locally, and emit an event to update the UI. If an issue arises in any of the calls, the entire chain is marked as a failure, and the local sites are NOT updated.

I suggest keeping the logic as simple as possible. Imagine you have 100+ sites in the app. The Sites pill indicates 100+ sites, and at some point, you perform a pull to refresh, or the app updates the sites upon opening the Reader. If an error occurs during a middle call, you will see fewer sites than before without a clear explanation.

Copy link
Contributor Author

@wargcm wargcm Mar 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll update it to fail if one of the pages doesn't succeed. It'll just use the first error we encounter. Updated in: 648e6cf.

Which error does Android use if multiple of the calls fail? I could see the logic getting pretty complicated if we tried to take each into account.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly on Android, we log the first error encountered, even though we don't actually propagate the error to the UI.

            public void onErrorResponse(VolleyError volleyError) {
                AppLog.e(AppLog.T.READER, volleyError);
                serverBlogs.clear();
                taskCompleted(UpdateTask.FOLLOWED_BLOGS);
            }

@wargcm
Copy link
Contributor Author

wargcm commented Mar 19, 2024

I installed this PR by updating from an older one and then navigated to the Reader. As expected, the Subscriptions feed was already selected, since i was already in that feed in the old version of the app. However, despite waiting, the Site pill did not update. Attempting to pull to refresh did nothing. Even force closing the app and restarting it did not resolve the issue.
I had to return to the Discovery feed and then go back to Subscriptions to get the pill updated.

This is a separate issue with the chip not updating and is being addressed in: #22829.

On my test account (the one I've shared internally), a couple of sites are not properly displayed in the site selector (see the picture below). When I select one of those sites, I get the "No posts" screen.

We've noticed this sometimes occurs too, but we aren't sure why either. It's an existing issue that should be unrelated to these changes. We could probably add some sort of filter to that list to remove the empty sites, but I'm not sure if we ever run into a scenario where one of those empty sites actually has content. If we did, then hiding them wouldn't be ideal because then the user wouldn't be able to individually view that site.

@wargcm wargcm force-pushed the issue/15651-update-following-mine branch 2 times, most recently from 9aa9fc6 to 648e6cf Compare March 19, 2024 20:40
@dvdchr dvdchr marked this pull request as ready for review March 29, 2024 16:46
wargcm and others added 3 commits March 30, 2024 01:17
Previously, the API call was only returning the first page of a user's
followed sites. This change adds support for a page parameter and uses
that to fetch all the pages at the same time.

Author:    Chris McGraw <2454408+wargcm@users.noreply.github.com>
@dvdchr dvdchr force-pushed the issue/15651-update-following-mine branch from 648e6cf to 259c480 Compare March 29, 2024 18:19
@dvdchr
Copy link
Contributor

dvdchr commented Mar 29, 2024

Heads up: with 259c480 I've updated the WordPressKit dependency to point to wordpress-mobile/WordPressKit-iOS@c2a51c2 now that wordpress-mobile/WordPressKit-iOS#753 is merged.

Since it's been pre-approved before, I'll set this PR on auto-merge on behalf of @wargcm.

@dvdchr dvdchr enabled auto-merge March 29, 2024 18:21
@dvdchr dvdchr merged commit 0d5e0c2 into trunk Mar 29, 2024
21 of 24 checks passed
@dvdchr dvdchr deleted the issue/15651-update-following-mine branch March 29, 2024 18:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Reader: Following Sites list is incomplete
5 participants