import 'package:didvan/constants/assets.dart'; import 'package:didvan/models/enums.dart'; import 'package:didvan/models/new_statistic/new_statistics_model.dart'; import 'package:didvan/providers/core.dart'; import 'package:didvan/services/content/content_service.dart'; import 'package:didvan/services/market/statista_market_service.dart'; import 'package:didvan/views/home/new_statistic/widgets/statistic_cat.dart'; import 'dart:async'; import 'package:flutter/foundation.dart'; class NewStatisticState extends CoreProvier { final List contents = []; DateTime? generatedAt; String? errorMessage; /// Signed URL of the «نبض صنعت» banner, managed from the panel /// (`/panel/market-symbols`). Null while loading or when unset. String? bannerUrl; /// Title of the content-category that holds the banner. Resolved by title so /// no UUID needs to be hardcoded — the panel creates it on first upload. static const String _bannerCategoryTitle = 'بنر نبض صنعت'; static String? _cachedBannerCategoryId; Future getBanner() async { try { final categoryId = await _resolveBannerCategoryId(); if (categoryId == null) return; final res = await ContentService.instance.getContents( page: 1, limit: 1, categoryId: categoryId, sortBy: const [MapEntry('createdAt', 'DESC')], ); if (!res.isSuccess || res.data == null || res.data!.data.isEmpty) { bannerUrl = null; notifyListeners(); return; } final first = res.data!.data.first; var cover = first.coverImage; if (cover == null || cover.isEmpty) { // The list endpoint does not always sign the cover; the detail one does. final detail = await ContentService.instance.getContent(first.id); if (detail.isSuccess && detail.data != null) { cover = detail.data!.coverImage; } } bannerUrl = (cover != null && cover.isNotEmpty) ? cover : null; notifyListeners(); } catch (e) { debugPrint('industry pulse banner failed: $e'); } } Future _resolveBannerCategoryId() async { if (_cachedBannerCategoryId != null) return _cachedBannerCategoryId; final res = await ContentService.instance.getCategories(limit: 100); if (!res.isSuccess || res.data == null) return null; for (final c in res.data!) { if (c.name == _bannerCategoryTitle && c.id != null) { _cachedBannerCategoryId = c.id; return c.id; } } return null; } List statCat = []; Future getStatistic() async { appState = AppState.busy; errorMessage = null; // Banner is independent of the price feed — fire and forget. unawaited(getBanner()); final result = await StatistaMarketService.instance.getLatestPrices(); if (result.isSuccess) { contents ..clear() ..addAll(result.categories); generatedAt = result.generatedAt; appState = AppState.idle; return; } contents.clear(); errorMessage = result.errorMessage; appState = AppState.idle; } void init() { statCat = [ StatMenuItemType( label: "بازار ارز و طلا", asset: Assets.currencyGoldStatCat, id: 1), StatMenuItemType( label: "ارزهای دیجیتال", asset: Assets.cryptoStatCat, id: 2), StatMenuItemType(label: "فلزات پایه", asset: Assets.metalStatCat, id: 3), StatMenuItemType( label: "کامودیتی‌ها", asset: Assets.commodityStatCat, id: 4), StatMenuItemType(label: "صنعت فولاد", asset: Assets.steelStatCat, id: 5), StatMenuItemType( label: "بازار سرمایه", asset: Assets.stockStatCat, id: 6), ]; Future.delayed(Duration.zero, () { getStatistic(); }); } void refresh() { statCat = [ StatMenuItemType( label: "بازار ارز و طلا", asset: Assets.currencyGoldStatCat, id: 1), StatMenuItemType( label: "ارزهای دیجیتال", asset: Assets.cryptoStatCat, id: 2), StatMenuItemType(label: "فلزات پایه", asset: Assets.metalStatCat, id: 3), StatMenuItemType( label: "کامودیتی‌ها", asset: Assets.commodityStatCat, id: 4), StatMenuItemType(label: "صنعت فولاد", asset: Assets.steelStatCat, id: 5), StatMenuItemType( label: "بازار سرمایه", asset: Assets.stockStatCat, id: 6), ]; update(); } void resetState() { contents.clear(); notifyListeners(); getStatistic(); } }