From 8336987f86850201f8597883091a6afd62db7e8b Mon Sep 17 00:00:00 2001 From: "Mr.Jebelli" Date: Mon, 22 Jun 2026 10:47:19 +0330 Subject: [PATCH] =?UTF-8?q?UUID=20dispatch=20before=20link/legacy=20?= =?UTF-8?q?=E2=80=94=20didvanplus=20+=20monthly=20with=20link=20now=20rout?= =?UTF-8?q?e=20correctly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../home_widget_repository.dart | 219 +++++++++--------- 1 file changed, 107 insertions(+), 112 deletions(-) diff --git a/lib/services/app_home_widget/home_widget_repository.dart b/lib/services/app_home_widget/home_widget_repository.dart index 631774a..a69c0ae 100644 --- a/lib/services/app_home_widget/home_widget_repository.dart +++ b/lib/services/app_home_widget/home_widget_repository.dart @@ -234,126 +234,121 @@ class HomeWidgetRepository { dynamic args; bool openComments = localData.notificationType.toString() == "2"; - if (localData.link.toString().isEmpty || - localData.link.toString() == "null") { - // ---------------- UUID short-circuit ---------------- - // Content from the new content-service uses UUIDs. The legacy routes - // below assume int IDs and can't be reached for UUID content. Route - // by `type` to the matching detail screen, all of which know how to - // hydrate from content-service when given `contentUuid`. - // - // Exception: trend / technology / startup intentionally render in - // their dedicated webview — those fall through to the legacy switch - // below so the URL is constructed and opened in a WebView even when - // the id is a UUID. - const _webViewTypes = {'trend', 'technology', 'startup'}; - final _isWebViewType = _webViewTypes.contains(localData.type); - if (_isUuid(localData.id) && !_isWebViewType) { - // Per-category routing for new (UUID-based) content. Each branch - // 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; + // ---------------- UUID dispatch (FIRST) ---------------- + // Content from the new content-service uses UUIDs. We must decide on + // the destination BEFORE checking `link`, because some categories + // (didvanplus / video / monthly) legitimately ship with a `link` (the + // media URL) and would otherwise get sent to a generic WebView, which + // breaks Arvan signed URLs. + // + // Exception: trend / technology / startup are NOT in-app screens — + // they live on app.didvan.com and we open them in a WebView, even + // when the id is a UUID. + const _webViewTypes = {'trend', 'technology', 'startup'}; + final _isWebViewType = _webViewTypes.contains(localData.type); + final _isUuidId = _isUuid(localData.id); + final _hasLink = localData.link != null && + localData.link!.isNotEmpty && + localData.link!.toString() != 'null'; - // Infography & banner: the existing InfographyDetails already - // knows how to load by UUID. - case 'infography': - case 'banner': - route = Routes.infographyDetails; - args = { - 'contentUuid': localData.id, - 'link': localData.link, - 'goToComment': openComments, - }; - break; + if (_isUuidId && !_isWebViewType) { + final type = localData.type ?? ''; + switch (type) { + 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; - // Podcast detail page. - case 'podcast': - route = Routes.studioDetails; - args = { - 'type': 'podcast', - 'contentUuid': localData.id, - 'goToComment': openComments, - }; - break; + case 'infography': + case 'banner': + route = Routes.infographyDetails; + args = { + 'contentUuid': localData.id, + 'link': localData.link, + 'goToComment': openComments, + }; + break; - // Video / video-cast detail page. - case 'video': - route = Routes.videoDetails; - args = { - 'contentUuid': localData.id, - 'goToComment': openComments, - }; - break; + case 'podcast': + route = Routes.studioDetails; + args = { + 'type': 'podcast', + 'contentUuid': localData.id, + 'goToComment': openComments, + }; + break; - // Monthly notifications normally arrive with `link` populated and - // go to PDFViewer in the `else` branch below. Reaching here means - // there's no PDF URL yet — show the list so the user can browse. - case 'monthly': + case 'video': + route = Routes.videoDetails; + args = { + '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; - break; + } + break; - case 'didvanplus': - // Open the player directly. We don't have a full DidvanPlusModel - // here (no record in the legacy DB), so we synthesize one from - // the notification payload — the player only reads file/image/ - // title/description. - if (localData.link != null && localData.link!.isNotEmpty) { - route = Routes.didvanPlusVideo; - args = DidvanPlusModel( - id: 0, // unused for navigation - title: localData.title ?? '', - description: localData.body ?? '', - image: localData.imageUrl ?? '', - file: localData.link!, - publishedAt: DateTime.now().toIso8601String(), - ); - } else { - // Fallback: no video URL → just show the list. - route = Routes.didvanPlusList; - } - break; + case 'didvanplus': + // Open the player directly with a synthesized model. + if (_hasLink) { + route = Routes.didvanPlusVideo; + args = DidvanPlusModel( + id: 0, // unused for navigation + title: localData.title ?? '', + description: localData.body ?? '', + image: localData.imageUrl ?? '', + file: localData.link!, + publishedAt: DateTime.now().toIso8601String(), + ); + } else { + route = Routes.didvanPlusList; + } + break; - case 'didvanvoice': - case 'media': - route = Routes.didvanVoiceList; - break; + case 'didvanvoice': + case 'media': + route = Routes.didvanVoiceList; + break; - // Unknown type with a UUID — best effort: generic reader. - default: - if (kDebugMode) { - print("UUID with unmapped type='$type' — defaulting to " - "InfographyDetails"); - } - route = Routes.infographyDetails; - args = { - 'contentUuid': localData.id, - 'link': localData.link, - 'goToComment': openComments, - }; - } - if (kDebugMode) { - print("UUID notification routed: type=$type → route=$route"); - } - } else if (localData.type == null || localData.type!.isEmpty) { + // Unknown type with a UUID — best effort: generic reader. + default: + if (kDebugMode) { + print("UUID with unmapped type='$type' — defaulting to " + "InfographyDetails"); + } + route = Routes.infographyDetails; + args = { + 'contentUuid': localData.id, + 'link': localData.link, + 'goToComment': openComments, + }; + } + if (kDebugMode) { + print("UUID notification routed: type=$type → route=$route"); + } + } 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) { print("=== NAVIGATION ABORTED ==="); print("Reason: Notification type is null or empty");