getApplicationCatalog method
Fetches every application category and browser-openable application available to the current portal account in Chinese and English.
The portal stores language in the server session, so implementations switch and fetch the two languages sequentially, merge by stable portal identifiers, and restore the user's original portal language before returning. SSO operations are serialized with these temporary switches so browser handoff keeps its established language behavior. English is optional: when that fetch is unavailable, Chinese data is still returned. Portal folders are traversed recursively. The portal's own bookmark state is intentionally not read or changed; favorites in Tattoo are app-local data managed by the repository.
Requires an active portal session (call login first).
Implementation
@override
Future<List<PortalApplicationCategoryDto>> getApplicationCatalog() {
return _withPortalLocaleLock(() async {
final initialResponse = await _getApplicationPage(
queryParameters: {'init': ''},
);
final initialDocument = _parseApplicationPage(initialResponse.data!);
final originalLocale = _parsePortalLocale(initialDocument);
var localeMutationAttempted = false;
Object? operationError;
try {
List<_PortalApplicationCategoryPageDto> english = const [];
late final List<_PortalApplicationCategoryPageDto> chinese;
if (originalLocale == _englishLocale) {
try {
english = await _getApplicationCatalogForCurrentLocale(
categoryDocument: initialDocument,
);
} on SessionExpiredException {
rethrow;
} catch (_) {
// English is optional; continue with the canonical Chinese crawl.
}
localeMutationAttempted = true;
await _setPortalLocale(_chineseLocale);
chinese = await _getApplicationCatalogForCurrentLocale();
} else {
chinese = await _getApplicationCatalogForCurrentLocale(
categoryDocument: initialDocument,
);
localeMutationAttempted = true;
await _setPortalLocale(_englishLocale);
try {
english = await _getApplicationCatalogForCurrentLocale();
} on SessionExpiredException {
rethrow;
} catch (_) {
// Match CourseService's bilingual behavior: English enriches the
// canonical Chinese response, but its instability must not make
// the complete catalog unavailable.
}
}
return _mergeApplicationCatalog(chinese, english);
} catch (error) {
operationError = error;
rethrow;
} finally {
if (localeMutationAttempted) {
try {
await _setPortalLocale(originalLocale);
} catch (restoreError, restoreStackTrace) {
_portalLocaleStateUncertain = true;
// Preserve the root failure when both the crawl and cleanup fail.
// If the crawl succeeded, fail the refresh so the repository does
// not mark an uncertain portal session state as freshly cached.
if (operationError == null) {
Error.throwWithStackTrace(restoreError, restoreStackTrace);
}
}
}
}
});
}