UUID dispatch before link/legacy — didvanplus + monthly with link now route correctly

This commit is contained in:
Mohamad Mahdi Jebeli 2026-06-22 10:47:19 +03:30
parent 7710b5cab8
commit 8336987f86
1 changed files with 107 additions and 112 deletions

View File

@ -234,126 +234,121 @@ class HomeWidgetRepository {
dynamic args; dynamic args;
bool openComments = localData.notificationType.toString() == "2"; bool openComments = localData.notificationType.toString() == "2";
if (localData.link.toString().isEmpty || // ---------------- UUID dispatch (FIRST) ----------------
localData.link.toString() == "null") { // Content from the new content-service uses UUIDs. We must decide on
// ---------------- UUID short-circuit ---------------- // the destination BEFORE checking `link`, because some categories
// Content from the new content-service uses UUIDs. The legacy routes // (didvanplus / video / monthly) legitimately ship with a `link` (the
// below assume int IDs and can't be reached for UUID content. Route // media URL) and would otherwise get sent to a generic WebView, which
// by `type` to the matching detail screen, all of which know how to // breaks Arvan signed URLs.
// hydrate from content-service when given `contentUuid`. //
// // Exception: trend / technology / startup are NOT in-app screens
// Exception: trend / technology / startup intentionally render in // they live on app.didvan.com and we open them in a WebView, even
// their dedicated webview those fall through to the legacy switch // when the id is a UUID.
// below so the URL is constructed and opened in a WebView even when const _webViewTypes = {'trend', 'technology', 'startup'};
// the id is a UUID. final _isWebViewType = _webViewTypes.contains(localData.type);
const _webViewTypes = {'trend', 'technology', 'startup'}; final _isUuidId = _isUuid(localData.id);
final _isWebViewType = _webViewTypes.contains(localData.type); final _hasLink = localData.link != null &&
if (_isUuid(localData.id) && !_isWebViewType) { localData.link!.isNotEmpty &&
// Per-category routing for new (UUID-based) content. Each branch localData.link!.toString() != 'null';
// sends the user to that category's native detail screen, all of
// which can hydrate from content-service via `contentUuid`.
//
// Categories whose detail screen isn't UUID-aware yet fall through
// to InfographyDetails (the generic content reader). When you wire
// a new screen, add another case here.
final type = localData.type ?? '';
switch (type) {
// Hard news / story / poyesh / swot all live in the NewsDetails
// pager same UI, different category filter.
case 'news':
case 'story':
case 'poyesh':
case 'swot':
route = Routes.newsDetails;
args = {
'contentUuid': localData.id,
'args': const NewsRequestArgs(page: 0),
'link': localData.link,
'goToComment': openComments,
};
break;
// Infography & banner: the existing InfographyDetails already if (_isUuidId && !_isWebViewType) {
// knows how to load by UUID. final type = localData.type ?? '';
case 'infography': switch (type) {
case 'banner': case 'news':
route = Routes.infographyDetails; case 'story':
args = { case 'poyesh':
'contentUuid': localData.id, case 'swot':
'link': localData.link, route = Routes.newsDetails;
'goToComment': openComments, args = {
}; 'contentUuid': localData.id,
break; 'args': const NewsRequestArgs(page: 0),
'link': localData.link,
'goToComment': openComments,
};
break;
// Podcast detail page. case 'infography':
case 'podcast': case 'banner':
route = Routes.studioDetails; route = Routes.infographyDetails;
args = { args = {
'type': 'podcast', 'contentUuid': localData.id,
'contentUuid': localData.id, 'link': localData.link,
'goToComment': openComments, 'goToComment': openComments,
}; };
break; break;
// Video / video-cast detail page. case 'podcast':
case 'video': route = Routes.studioDetails;
route = Routes.videoDetails; args = {
args = { 'type': 'podcast',
'contentUuid': localData.id, 'contentUuid': localData.id,
'goToComment': openComments, 'goToComment': openComments,
}; };
break; break;
// Monthly notifications normally arrive with `link` populated and case 'video':
// go to PDFViewer in the `else` branch below. Reaching here means route = Routes.videoDetails;
// there's no PDF URL yet — show the list so the user can browse. args = {
case 'monthly': 'contentUuid': localData.id,
'goToComment': openComments,
};
break;
case 'monthly':
// PDF URL is in `link`; if present, open PdfViewer directly.
if (_hasLink) {
route = Routes.pdfViewer;
args = {
'pdfUrl': localData.link,
'title': localData.title ?? 'ماهنامه',
};
} else {
route = Routes.monthlyList; route = Routes.monthlyList;
break; }
break;
case 'didvanplus': case 'didvanplus':
// Open the player directly. We don't have a full DidvanPlusModel // Open the player directly with a synthesized model.
// here (no record in the legacy DB), so we synthesize one from if (_hasLink) {
// the notification payload the player only reads file/image/ route = Routes.didvanPlusVideo;
// title/description. args = DidvanPlusModel(
if (localData.link != null && localData.link!.isNotEmpty) { id: 0, // unused for navigation
route = Routes.didvanPlusVideo; title: localData.title ?? '',
args = DidvanPlusModel( description: localData.body ?? '',
id: 0, // unused for navigation image: localData.imageUrl ?? '',
title: localData.title ?? '', file: localData.link!,
description: localData.body ?? '', publishedAt: DateTime.now().toIso8601String(),
image: localData.imageUrl ?? '', );
file: localData.link!, } else {
publishedAt: DateTime.now().toIso8601String(), route = Routes.didvanPlusList;
); }
} else { break;
// Fallback: no video URL just show the list.
route = Routes.didvanPlusList;
}
break;
case 'didvanvoice': case 'didvanvoice':
case 'media': case 'media':
route = Routes.didvanVoiceList; route = Routes.didvanVoiceList;
break; break;
// Unknown type with a UUID best effort: generic reader. // Unknown type with a UUID best effort: generic reader.
default: default:
if (kDebugMode) { if (kDebugMode) {
print("UUID with unmapped type='$type' — defaulting to " print("UUID with unmapped type='$type' — defaulting to "
"InfographyDetails"); "InfographyDetails");
} }
route = Routes.infographyDetails; route = Routes.infographyDetails;
args = { args = {
'contentUuid': localData.id, 'contentUuid': localData.id,
'link': localData.link, 'link': localData.link,
'goToComment': openComments, 'goToComment': openComments,
}; };
} }
if (kDebugMode) { if (kDebugMode) {
print("UUID notification routed: type=$type → route=$route"); print("UUID notification routed: type=$type → route=$route");
} }
} else if (localData.type == null || localData.type!.isEmpty) { } else if (!_hasLink) {
// Legacy int-id branch: no link, fall through to per-type detail
// pages keyed by int id (or home if no type).
if (localData.type == null || localData.type!.isEmpty) {
if (kDebugMode) { if (kDebugMode) {
print("=== NAVIGATION ABORTED ==="); print("=== NAVIGATION ABORTED ===");
print("Reason: Notification type is null or empty"); print("Reason: Notification type is null or empty");