The old refresh path called MibContactsClient.fetchContacts() per
profile, which greedily walked every page and stuffed the union into
the contacts cache in one shot. A user with several hundred or several
thousand MIB beneficiaries paid for N round-trips before the screen
could render, and the cache write encrypted the whole blob each time.
Introduces a paginator that streams contacts on demand:
* MibContactsClient.fetchContactsPage(session, start, count) — single
page; fetchContacts() now layers on top for callers that want all
pages.
* MibContactsPaginator — walks the user's MIB profiles serially under
the existing mibMutex, returning one page per nextPage() call.
Categories are accumulated across calls.
* HomeActivity.refreshContacts now requests just the first page
(default 30 contacts) per login. Subsequent pages arrive via
HomeActivity.loadMoreMibContacts(), which ContactsFragment fires
from a scroll listener when the user is within 5 rows of the end
of any tab. NEXT_PAGE_SIZE is 100 — matches the API's natural
page size.
* ContactsCache.appendContacts merges a new page into the cached
list (dedupe by benefNo) instead of overwriting. The first page
of a refresh still uses save() so deletions take effect.
* HomeViewModel exposes mibContactsLoading / mibContactsHasMore
so the fragment can show a loading footer (item_loading_footer)
on each contact tab while a page is in flight.
* ContactsAdapter grows a showLoadingFooter flag and a second view
type for the footer row.
Search remains client-side over the loaded set — results may be
partial until the user keeps scrolling. The MIB API supports
server-side search via the `search` parameter but wiring it in is a
separate change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This pull request has changes conflicting with the target branch.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The old refresh path called MibContactsClient.fetchContacts() per profile, which greedily walked every page and stuffed the union into the contacts cache in one shot. A user with several hundred or several thousand MIB beneficiaries paid for N round-trips before the screen could render, and the cache write encrypted the whole blob each time. Introduces a paginator that streams contacts on demand: * MibContactsClient.fetchContactsPage(session, start, count) — single page; fetchContacts() now layers on top for callers that want all pages. * MibContactsPaginator — walks the user's MIB profiles serially under the existing mibMutex, returning one page per nextPage() call. Categories are accumulated across calls. * HomeActivity.refreshContacts now requests just the first page (default 30 contacts) per login. Subsequent pages arrive via HomeActivity.loadMoreMibContacts(), which ContactsFragment fires from a scroll listener when the user is within 5 rows of the end of any tab. NEXT_PAGE_SIZE is 100 — matches the API's natural page size. * ContactsCache.appendContacts merges a new page into the cached list (dedupe by benefNo) instead of overwriting. The first page of a refresh still uses save() so deletions take effect. * HomeViewModel exposes mibContactsLoading / mibContactsHasMore so the fragment can show a loading footer (item_loading_footer) on each contact tab while a page is in flight. * ContactsAdapter grows a showLoadingFooter flag and a second view type for the footer row. Search remains client-side over the loaded set — results may be partial until the user keeps scrolling. The MIB API supports server-side search via the `search` parameter but wiring it in is a separate change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.