import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart'; import 'package:go_router/go_router.dart'; import 'package:path_provider/path_provider.dart'; import 'package:pocketbase/pocketbase.dart'; import 'package:screenshot/screenshot.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; import 'package:uae_stat/config/api_config.dart'; import 'package:uae_stat/config/connectivity_provider.dart'; import 'package:uae_stat/config/toast_util.dart'; import 'package:uae_stat/config/toggle_lang_service.dart'; import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/infrastructure/services/img_asset_paths/icons/uae_numbers_asset_path.dart'; import 'package:uae_stat/presentation/Screens/charts/services/api_service.dart'; import 'package:uae_stat/presentation/Screens/charts/widgets/chart_widget.dart'; import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; import 'package:uae_stat/presentation/components/my_toggle.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; import 'package:uae_stat/presentation/Screens/app_tour/Target_content.dart'; import '../filters/search_filter_helper.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:share_plus/share_plus.dart'; import 'package:path_provider/path_provider.dart'; import 'dart:io'; class ChartScreen1 extends ConsumerStatefulWidget { final String dataSets; final String bgColor; final String mainTopic; final String title; final String? keyParam; // Nullable String final String kpi; final List> filter_data; const ChartScreen1({ Key? key, required this.dataSets, required String this.bgColor, required this.mainTopic, required this.title, required this.keyParam, required this.kpi, required this.filter_data, }); @override ConsumerState createState() => _ChartScreen1State(); } class _ChartScreen1State extends ConsumerState { // final _pb = PocketBase('https://pb.venbait.in'); final _pb = PocketBase(apiUrl); final GlobalKey _scaffoldKey = GlobalKey(); final ApiService apiService = ApiService(); bool isLoading = true; bool _isSharing = false; List isChartData = []; List nonChartData = []; Map chartScreenData = {}; List filterDataSet = []; List filterData = []; List chartsData = []; List tabFilteredChartData = []; List tabFilteredCardData = []; List cardData = []; List> filteredAndSortedData = []; List> selectedFiltersStorage = []; List> selectedFiltersApi = []; List originalChartsData = []; List originalCardData = []; List originalTabCardData = []; List originalTabChartsData = []; late Color backgroundColor; final ScrollController _scrollController = ScrollController(); int _activeTabIndex = 0; dynamic tabWiseKpi = []; dynamic tabFilteredKpi = []; List> formattedFilters = []; dynamic _tabsData = []; dynamic currentTab = []; // List> _tabsData = []; late List marriageTargets; late List previousMarriageTargets; late TutorialCoachMark tutorialCoachMark; final GlobalKey chartKey = GlobalKey(); final GlobalKey bookMarkKey = GlobalKey(); final GlobalKey cardKey = GlobalKey(); bool isBookmarked = false; // Track bookmark state String? bookmarkId; // Stores the ID of the bookmark record in PocketBase late final Locale locale; late String mainTopic; late UserService _userService; late double tourCard; @override void initState() { super.initState(); _userService = UserService(); final String bgColor = widget.bgColor; print(' bgColor $bgColor'); checkIfBookmarked(); locale = ref.read(localeProvider) ?? const Locale('en'); print('locale-$locale'); fetchChartData(widget.dataSets, locale?.languageCode ?? 'en', widget.kpi, widget.filter_data) .then((_) { if (_tabsData.isNotEmpty) { // Call onTabSelected for the first tab onTabSelected(_tabsData[0]['id']); } }); WidgetsBinding.instance.addPostFrameCallback((_) { _startTutorialAfterRender(); }); } /// Check if the item is already bookmarked Future checkIfBookmarked() async { final prefs = await SharedPreferences.getInstance(); final userID = prefs.getString('userId'); try { final adminAuth = await _pb.admins.authWithPassword( 'pb@venbainfotech.com', 'pb@venbainfotech.com', ); final adminToken = adminAuth.token; final result = await _pb.collection('bookmark').getList( filter: "user_id = '${userID}' && dataset = '${widget.dataSets}'", headers: { 'Authorization': adminToken, // Pass the admin token }, ); if (result.items.isNotEmpty) { setState(() { isBookmarked = true; bookmarkId = result.items.first.id; }); } } catch (e) { print("Error checking bookmark: $e"); } } /// Add bookmark to PocketBase Future addBookmark() async { final prefs = await SharedPreferences.getInstance(); final userID = prefs.getString('userId'); try { final adminAuth = await _pb.admins .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); final adminToken = adminAuth.token; final response = await _pb.collection('bookmark').create(body: { 'user_id': userID, 'dataset': widget.dataSets, 'bgColor': widget.bgColor, 'mainTopic': widget.mainTopic, 'title': widget.title, 'keyParam': widget.keyParam, }, headers: { 'Authorization': adminToken }); setState(() { isBookmarked = true; bookmarkId = response.id; }); // ToastUtil.showSuccessToast("Added to Bookmark."); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( AppLocalizations.of(context)!.added_to_Bookmark, style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ) ), ), duration: Duration(seconds: 2), ), ); print("Bookmark added: ${response.id}"); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( AppLocalizations.of(context)!.failed_To_Remove, style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ) ), ), // backgroundColor: Color(0xFFEB5F24), duration: Duration(seconds: 2), ), ); // ToastUtil.showDeleteToast("Unable to add to bookmarks. Please try again"); print("Error adding bookmark: $e"); } } /// Remove bookmark from PocketBase Future removeBookmark() async { try { final adminAuth = await _pb.admins .authWithPassword('pb@venbainfotech.com', 'pb@venbainfotech.com'); final adminToken = adminAuth.token; if (bookmarkId != null) { await _pb.collection('bookmark').delete(bookmarkId!, headers: { 'Authorization': adminToken, }); setState(() { isBookmarked = false; bookmarkId = null; }); // ToastUtil.showSuccessToast("Removed from Bookmark."); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( AppLocalizations.of(context)!.removed_from_Bookmark, style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ) ), ), duration: Duration(seconds: 2), ), ); print("Bookmark removed"); } } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Failed to Remove', style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ) ), ), // backgroundColor: Color(0xFFEB5F24), duration: Duration(seconds: 2), ), ); // ToastUtil.showDeleteToast( // "Unable to remove from bookmarks. Please try again"); print("Error removing bookmark: $e"); } } /// Show confirmation dialog before removing bookmark void showRemoveBookmarkDialog() { double myheight = MediaQuery.of(context).size.height; showDialog( context: context, barrierDismissible: false, // User must tap button to dismiss dialog builder: (context) => AlertDialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(5.0), // Rounded corners ), contentPadding: EdgeInsets.zero, content: Stack( children: [ Padding( padding: const EdgeInsets.all(10.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox( height: myheight / 30, ), Text( context.translate( 'Are you sure you want to remove this bookmark?', 'هل أنت متأكد أنك تريد إزالة هذه الإشارة المرجعية؟'), textAlign: TextAlign.center, style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), fontSize: 18, color: Color(0xFF898C81), ), ) ], ), ), ], ), actions: [ SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ SizedBox( width: 100, // Set the desired width child: TextButton( onPressed: () => Navigator.pop(context), style: TextButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( 10.0), // Adjust the radius as needed ), side: BorderSide( color: Color(0xFFAA8E83), // Set the outline color width: 1, // Set the border width ), ), child: Text( context.translate('No', 'لا'), style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), color: Color(0xFFAA8E83), fontSize: 16, ), ), ), ), SizedBox( width: 100, // Set the desired width child: TextButton( onPressed: () { Navigator.pop(context); removeBookmark(); // Close dialog }, style: TextButton.styleFrom( backgroundColor: Color(0xFFAA8E83), // Set background color foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0), // Set text color ), ), child: Text( context.translate('Yes', 'نعم'), style: TextStyle(color: Colors.white, fontSize: 16, fontFamily: context.translate( 'Roboto', 'NotoKufi', ),), ), ), ), ], ) ], ), ); } //when the popup need for bookmark void showAddBookmarkDialog() { double myheight = MediaQuery.of(context).size.height; showDialog( context: context, barrierDismissible: false, // User must tap button to dismiss dialog builder: (context) => AlertDialog( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(5.0), // Rounded corners ), contentPadding: EdgeInsets.zero, content: Stack( children: [ Padding( padding: const EdgeInsets.all(10.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox( height: myheight / 30, ), Text( context.translate( 'Do you want to add this to bookmarks?', 'هل تريد إضافة هذا إلى الإشارات المرجعية؟', ), textAlign: TextAlign.center, style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), fontSize: 18, color: Color(0xFF898C81), ), ) ], ), ), ], ), actions: [ SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ SizedBox( width: 100, // Set the desired width child: TextButton( onPressed: () => Navigator.pop(context), style: TextButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular( 10.0), // Adjust the radius as needed ), side: BorderSide( color: Color(0xFFAA8E83), // Set the outline color width: 1, // Set the border width ), ), child: Text( context.translate('No', 'لا'), style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), color: Color(0xFFAA8E83), fontSize: 16, ), ), ), ), SizedBox( width: 100, // Set the desired width child: TextButton( onPressed: () { Navigator.pop(context); addBookmark(); // Close dialog }, style: TextButton.styleFrom( backgroundColor: Color(0xFFAA8E83), // Set background color foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10.0), // Set text color ), ), child: Text( context.translate('Yes', 'نعم'), style: TextStyle(color: Colors.white, fontSize: 16, fontFamily: context.translate( 'Roboto', 'NotoKufi', ),), ), ), ), ], ), ], ), ); } // void showAddBookmarkDialog() { // addBookmark(); // // ScaffoldMessenger.of(context).showSnackBar( // // SnackBar( // // content: Text( // // 'The bookmark is added successfully', // // ), // // backgroundColor: Colors.green, // // duration: Duration(seconds: 2), // // ), // // ); // } ///Calculate card Width Future _getWidget() async { await Future.delayed(Duration(milliseconds: 50)); // Ensures widget is built final RenderBox? box = cardKey.currentContext?.findRenderObject() as RenderBox?; if (box != null) { final Offset position = box.localToGlobal(Offset.zero); final Size size = box.size; double bottomY = position.dy + size.height; // Y position + height // final double screenWidth = MediaQuery.of(context).size.width; // final double screenHeight = MediaQuery.of(context).size.height; // print("screenWidth: ${screenWidth}"); // print("screenHeight: ${screenHeight}"); // print("Widget Position: ${position.dx}, ${position.dy}"); // print("Widget Size: ${size.width} x ${size.height}"); // print("Bottom Y Position: $bottomY"); return bottomY; } return null; } Future handleSkip() async { tutorialCoachMark.skip(); debugPrint('Skip clicked'); final prefs = await SharedPreferences.getInstance(); String? loginCount = prefs.getString('login_count'); if (loginCount == '1') { await prefs.setString('login_count', '2'); } ref.read(chartsTourProvider.notifier).state = true; ref.read(previousChartsTourProvider.notifier).state = true; ref.read(homeTourProvider.notifier).state = true; ref.read(previousHomeTourProvider.notifier).state = true; ref.read(scaffoldTourProvider.notifier).state = true; ref.read(previousScaffoldTourProvider.notifier).state = true; context.go('/myhomepage'); } Future _kpiTutorialCoachMark() async { debugPrint('Not Initialized and Started'); tourCard = (await _getWidget())!; // _calculateMarkPosition(); _initmarriageTargets(); debugPrint('Initialized and Started'); tutorialCoachMark = TutorialCoachMark( paddingFocus: 0, useSafeArea: true, pulseEnable: false, hideSkip: true, targets: marriageTargets, onFinish: () { context.go('/myhomepage'); debugPrint('Marriage Tutorial Finished'); }, )..show(context: context); } void _startTutorialAfterRender() { final chartTour = ref.watch(chartsTourProvider); final previousChartTour = ref.watch(previousChartsTourProvider); debugPrint('render problem'); if (cardKey.currentContext != null && !chartTour) { _kpiTutorialCoachMark(); } else if (cardKey.currentContext != null && !previousChartTour) { _previousKpiTutorial(); } else if (!chartTour || !previousChartTour) { Future.delayed(Duration(milliseconds: 100), _startTutorialAfterRender); } else { return; } } Future _previousKpiTutorial() async { tourCard = (await _getWidget())!; _initpreviousTargets(); tutorialCoachMark = TutorialCoachMark( paddingFocus: 0, useSafeArea: true, pulseEnable: false, hideSkip: true, targets: previousMarriageTargets, onFinish: () { context.go('/myhomepage'); debugPrint('Previous Marriage Tutorial Finished'); }, )..show(context: context); } void _initmarriageTargets() { final double screenWidth = MediaQuery.of(context).size.width; final double screenHeight = MediaQuery.of(context).size.height; // print('remaintarget $remainHeight'); // print ('at intint target : ${screenHeight-remainHeight}'); final double arrowPosition = screenHeight - tourCard; marriageTargets = [ TargetFocus( enableTargetTab: false, identify: 'cardKey', keyTarget: cardKey, shape: ShapeLightFocus.RRect, radius: 8, paddingFocus: 0, contents: [ createTargetContent( text: AppLocalizations.of(context)!.kpiCards, alignment: ContentAlign.top, gap: 55, space: 0, ), TargetContent( align: ContentAlign.bottom, child: SizedBox( width: double.infinity, height: arrowPosition, child: Stack( children: [ Positioned( bottom: arrowPosition * 0.41, left: 16, right: 16, child: Column( children: [ Align( alignment: Alignment.bottomRight, child: Padding( padding: EdgeInsets.only(right: 10), child: Text( '3/7', style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), color: Colors.white, fontSize: 14, ), ), ), ), const SizedBox(height: 5), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ElevatedButton( onPressed: () => handleSkip(), style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), side: const BorderSide(color: Colors.white), backgroundColor: Colors.transparent, elevation: 0, ), child: Text( AppLocalizations.of(context)!.skip, style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), color: Colors.white, fontSize: 14, ), ), ), Row( children: [ Container( decoration: BoxDecoration( shape: BoxShape.circle, color: locale.languageCode == 'ar' ? Color(0xFF7DAFBC) : null, border: Border.all( color: locale.languageCode == 'ar' ? Color(0xFF7DAFBC) : Colors.white, width: 2.0), ), child: IconButton( iconSize: 20, icon: const Icon(Icons.arrow_back, color: Colors.white), onPressed: () { if (locale.languageCode == 'ar') { tutorialCoachMark.next(); } else { ref .read(chartsTourProvider.notifier) .state = true; ref .read(previousHomeTourProvider .notifier) .state = false; tutorialCoachMark.finish(); } }, ), ), const SizedBox(width: 10), Container( decoration: BoxDecoration( shape: BoxShape.circle, color: locale.languageCode == 'ar' ? null : Color(0xFF7DAFBC), border: Border.all( color: locale.languageCode == 'ar' ? Colors.white : Color(0xFF7DAFBC), width: 1), ), child: IconButton( iconSize: 20, icon: const Icon(Icons.arrow_forward, color: Colors.white), onPressed: () { if (locale.languageCode == 'ar') { ref .read(chartsTourProvider.notifier) .state = true; ref .read(previousHomeTourProvider .notifier) .state = false; tutorialCoachMark.finish(); } else { tutorialCoachMark.next(); } }, ), ), ], ), ], ), ], ), ), ], ), ), ), TargetContent( padding: EdgeInsets.only( bottom: 0, top: 0, ), align: ContentAlign.top, child: SizedBox( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height * 0.69, child: Stack(children: [ Positioned( left: MediaQuery.of(context).size.width * 0.40, bottom: 0, child: Image.asset( 'assets/app_tour/leftUp.png', width: 100, height: 90, ), ), ]), ), ), ], ), TargetFocus( enableTargetTab: false, identify: 'BookMarkKey', keyTarget: bookMarkKey, shape: ShapeLightFocus.RRect, radius: 8, paddingFocus: 12, contents: [ createTargetContent( text: AppLocalizations.of(context)!.bookMark, alignment: ContentAlign.bottom, gap: 53, space: screenWidth * 0.22, ), TargetContent( align: ContentAlign.bottom, child: SizedBox( width: double.infinity, height: MediaQuery.of(context).size.height * 0.65, child: Stack( children: [ Positioned( bottom: 25, left: 16, right: 16, child: Column( children: [ Align( alignment: Alignment.bottomRight, child: Padding( padding: EdgeInsets.only(right: 10), child: Text( '4/7', style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), color: Colors.white, fontSize: 14, ), ), ), ), const SizedBox(height: 5), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ElevatedButton( onPressed: () => handleSkip(), style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), side: const BorderSide(color: Colors.white), backgroundColor: Colors.transparent, elevation: 0, ), child: Text( AppLocalizations.of(context)!.skip, style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), color: Colors.white, fontSize: 14, ), ), ), Row( children: [ Container( decoration: BoxDecoration( shape: BoxShape.circle, color: locale.languageCode == 'ar' ? Color(0xFF7DAFBC) : null, border: Border.all( color: locale.languageCode == 'ar' ? Color(0xFF7DAFBC) : Colors.white, width: 2.0), ), child: IconButton( iconSize: 20, icon: const Icon( Icons.arrow_back, color: Colors.white, ), onPressed: () { if (locale.languageCode == 'ar') { ref .read(chartsTourProvider.notifier) .state = true; ref .read(scaffoldTourProvider.notifier) .state = false; tutorialCoachMark.finish(); } else { tutorialCoachMark.previous(); } }, ), ), const SizedBox(width: 10), Container( decoration: BoxDecoration( shape: BoxShape.circle, color: locale.languageCode == 'ar' ? null : Color(0xFF7DAFBC), border: Border.all( color: locale.languageCode == 'ar' ? Colors.white : Color(0xFF7DAFBC), width: 1), ), child: IconButton( iconSize: 20, icon: const Icon( Icons.arrow_forward, color: Colors.white, ), onPressed: () { if (locale.languageCode == 'ar') { tutorialCoachMark.previous(); } else { ref .read(chartsTourProvider.notifier) .state = true; ref .read(scaffoldTourProvider.notifier) .state = false; tutorialCoachMark.finish(); } }, ), ), ], ), ], ), ], ), ), ], ), ), ), TargetContent( padding: EdgeInsets.only(left: 0, top: 0), align: ContentAlign.right, child: Container( width: screenWidth / 4, height: screenHeight * 0.2, child: Stack( children: [ Image.asset( 'assets/app_tour/leftDown.png', fit: BoxFit.contain, ), ], ), ), ), ], ), ]; } void _initpreviousTargets() { final double screenWidth = MediaQuery.of(context).size.width; final double screenHeight = MediaQuery.of(context).size.height; // print('remaintarget $remainHeight'); // print ('at intint target : ${screenHeight-remainHeight}'); final double arrowPosition = screenHeight - tourCard; previousMarriageTargets = [ TargetFocus( enableTargetTab: false, identify: 'BookMarkKey', keyTarget: bookMarkKey, shape: ShapeLightFocus.RRect, radius: 8, paddingFocus: 12, contents: [ createTargetContent( text: AppLocalizations.of(context)!.bookMark, space: screenWidth * 0.22, alignment: ContentAlign.bottom, gap: 53, ), TargetContent( align: ContentAlign.bottom, child: SizedBox( width: double.infinity, height: MediaQuery.of(context).size.height * 0.65, child: Stack( children: [ Positioned( bottom: 25, left: 16, right: 16, child: Column( children: [ Align( alignment: Alignment.bottomRight, child: Padding( padding: const EdgeInsets.only(right: 10.0), child: Text( '4/7', style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), color: Colors.white, fontSize: 14, ), ), ), ), const SizedBox(height: 5), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ElevatedButton( onPressed: () => handleSkip(), style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), side: const BorderSide(color: Colors.white), backgroundColor: Colors.transparent, elevation: 0, ), child: Text( AppLocalizations.of(context)!.skip, style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), color: Colors.white, fontSize: 14, ), ), ), Row( children: [ Container( decoration: BoxDecoration( shape: BoxShape.circle, color: locale.languageCode == 'ar' ? Color(0xFF7DAFBC) : null, border: Border.all( color: locale.languageCode == 'ar' ? Color(0xFF7DAFBC) : Colors.white, width: 2.0, ), ), child: IconButton( iconSize: 20, icon: const Icon( Icons.arrow_back, color: Colors.white, ), onPressed: () { if (locale.languageCode == 'ar') { ref .read(chartsTourProvider.notifier) .state = true; ref .read(scaffoldTourProvider.notifier) .state = false; tutorialCoachMark.finish(); } else { tutorialCoachMark.next(); } }, ), ), const SizedBox(width: 10), Container( decoration: BoxDecoration( shape: BoxShape.circle, color: locale.languageCode == 'ar' ? null : Color(0xFF7DAFBC), border: Border.all( color: locale.languageCode == 'ar' ? Colors.white : Color(0xFF7DAFBC), width: 2.0, ), ), child: IconButton( iconSize: 20, icon: const Icon(Icons.arrow_forward, color: Colors.white), onPressed: () { if (locale.languageCode == 'ar') { tutorialCoachMark.next(); } else { ref .read(chartsTourProvider.notifier) .state = true; ref .read(scaffoldTourProvider.notifier) .state = false; tutorialCoachMark.finish(); } }, ), ), ], ), ], ), ], ), ), ], ), ), ), TargetContent( padding: EdgeInsets.only(left: 0, top: 0), align: ContentAlign.right, child: SizedBox( width: screenWidth / 4, height: screenHeight * 0.2, child: Stack( children: [ Image.asset( 'assets/app_tour/leftDown.png', fit: BoxFit.contain, ), ], ), ), ), ], ), TargetFocus( enableTargetTab: false, identify: 'cardKey', keyTarget: cardKey, shape: ShapeLightFocus.RRect, radius: 8, paddingFocus: 0, contents: [ createTargetContent( text: AppLocalizations.of(context)!.kpiCards, space: 0, alignment: ContentAlign.top, gap: 55, ), TargetContent( align: ContentAlign.bottom, child: SizedBox( width: double.infinity, height: arrowPosition, child: Stack( children: [ Positioned( bottom: arrowPosition * 0.41, left: 16, right: 16, child: Column( children: [ Align( alignment: Alignment.bottomRight, child: Padding( padding: const EdgeInsets.only(right: 10.0), child: Text( '3/7', style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), color: Colors.white, fontSize: 14, ), ), ), ), const SizedBox(height: 5), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ ElevatedButton( onPressed: () => handleSkip(), style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), side: const BorderSide(color: Colors.white), backgroundColor: Colors.transparent, elevation: 0, ), child: Text( AppLocalizations.of(context)!.skip, style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), color: Colors.white, fontSize: 14, ), ), ), Row( children: [ Container( decoration: BoxDecoration( shape: BoxShape.circle, color: locale.languageCode == 'ar' ? Color(0xFF7DAFBC) : null, border: Border.all( color: locale.languageCode == 'ar' ? Color(0xFF7DAFBC) : Colors.white, width: 2.0, ), ), child: IconButton( iconSize: 20, icon: const Icon( Icons.arrow_back, color: Colors.white, ), onPressed: () { if (locale.languageCode == 'ar') { tutorialCoachMark.previous(); } else { ref .read(previousChartsTourProvider .notifier) .state = true; ref .read(previousHomeTourProvider .notifier) .state = false; tutorialCoachMark.finish(); } }, ), ), const SizedBox(width: 10), Container( decoration: BoxDecoration( shape: BoxShape.circle, color: locale.languageCode == 'ar' ? null : Color(0xFF7DAFBC), border: Border.all( color: locale.languageCode == 'ar' ? Colors.white : Color(0xFF7DAFBC), width: 1), ), child: IconButton( iconSize: 20, icon: const Icon( Icons.arrow_forward, color: Colors.white, ), onPressed: () { if (locale.languageCode == 'ar') { ref .read(previousChartsTourProvider .notifier) .state = true; ref .read(previousHomeTourProvider .notifier) .state = false; tutorialCoachMark.finish(); } else { tutorialCoachMark.previous(); } }, ), ), ], ), ], ), ], ), ), ], ), ), ), TargetContent( padding: EdgeInsets.only( bottom: 0, top: 0, ), align: ContentAlign.top, child: SizedBox( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height * 0.69, child: Stack(children: [ Positioned( left: MediaQuery.of(context).size.width * 0.40, bottom: 0, child: Image.asset( 'assets/app_tour/leftUp.png', width: 100, height: 90, ), ), ]), ), ), ], ), ]; } void _scrollToIndex(int index) { double scrollPosition = index * 120.0; // Adjust based on tab size _scrollController.animateTo( scrollPosition, duration: Duration(milliseconds: 300), curve: Curves.easeInOut, ); } void _scrollLeft() { if (_activeTabIndex > 0) { setState(() { _activeTabIndex--; }); _scrollToIndex(_activeTabIndex); onTabSelected(_tabsData[_activeTabIndex]['id']!); // Pass the tab's id print("TABFiltered Data: $filterData"); } } void _scrollRight() { if (_activeTabIndex < _tabsData.length - 1) { setState(() { _activeTabIndex++; }); _scrollToIndex(_activeTabIndex); onTabSelected(_tabsData[_activeTabIndex]['id']!); // Pass the tab's id } } // void processChartData(chartsData) { // // Group data by 'kpi' // Map>> groupedData = {}; // for (var chart in chartsData) { // String kpi = chart['kpi'] ?? ''; // if (!groupedData.containsKey(kpi)) { // groupedData[kpi] = []; // } // groupedData[kpi]!.add(chart); // } // // // Format 'kpi' values for _tabs // List> _tabs = groupedData.keys.map((kpi) { // String name = kpi // .split('_') // Split by underscore // .map( // (word) => word[0].toUpperCase() + word.substring(1)) // Capitalize // .join(' '); // Join words with space // // return {'id': kpi, 'name': name}; // }).toList(); // // print('Grouped Data: $groupedData'); // print('Tabs: $_tabs'); // setState(() { // _tabsData = _tabs; // }); // } void processChartData(chartsData) { print("PROCESSING FILTER CHART DATa"); // Group data by 'kpi' Map>> groupedData = {}; for (var chart in chartsData) { String kpi = chart['kpi'] ?? ''; if (!groupedData.containsKey(kpi)) { groupedData[kpi] = []; } groupedData[kpi]!.add(chart); } // Format 'kpi' values for _tabs with tab_heading List> _tabs = groupedData.entries.map((entry) { String kpi = entry.key; var firstChart = entry.value.first; // Extract tab_heading from the first chart in the grouped list String tabHeading = entry.value.isNotEmpty ? entry.value.first['tab_heading'] ?? 'Unknown' : 'Unknown'; int tabOrder = int.tryParse(firstChart['tab_order'] ?? '0') ?? 0; String formattedKpi = kpi .split('_') // Split by underscore .map((word) => word.isNotEmpty ? word[0].toUpperCase() + word.substring(1) : '') // Capitalize .join(' '); // Join words with space return {'id': kpi, 'name': tabHeading, 'order': tabOrder.toString()}; }).toList(); // Sort tabs by tab_order _tabs.sort((a, b) { int orderA = int.tryParse(a['order'] ?? '0') ?? 0; int orderB = int.tryParse(b['order'] ?? '0') ?? 0; return orderA.compareTo(orderB); }); print('Sorted Tabs: $_tabs'); // print('Grouped Data: $groupedData'); print('Tabs: $_tabs'); setState(() { _tabsData = _tabs; }); } Future fetchChartData(String dataSets, locale, kpi, filter_data) async { var data = await apiService.fetchChartData(dataSets, locale, kpi, filter_data); tabFilteredKpi = kpi; print('FETCH KPI- $kpi'); print('FETCH KFilter- $filter_data'); print('locale1 - $locale'); // print('locale11 - $loacleData'); // Store filter_data if it has a value if (filter_data != null && filter_data is List && filter_data.isNotEmpty) { selectedFiltersApi = filter_data.map>((entry) { if (entry is Map) { return entry.map( (key, value) => MapEntry(key.toString(), value)); } return {}; }).toList(); print('FETVCFILTEr: $selectedFiltersApi'); } if (data.containsKey('filterData')) { var filterData = data['filterData']; filterDataSet = filterData.entries .map((entry) => {'key': entry.key, 'value': entry.value}) .toList(); print("filterDataf1:- $filterData"); print("filterDataf11:- $filterDataSet"); } else { filterDataSet = data['filterData'] ?? []; print('filterData not found!'); } setState(() { isChartData = data['isChartData'] ?? []; nonChartData = data['nonChartData'] ?? []; // filterData = data['filterData'] ?? []; originalChartsData = List.from(isChartData); // Store original data originalCardData = List.from(nonChartData); chartsData = isChartData; cardData = nonChartData; chartScreenData = data['chartScreenData'] ?? {}; processChartData(chartsData); onTabSelected(tabFilteredKpi); print('chartsData :- $chartsData'); print('cardData :- $cardData'); print('chartScreenData :- $chartScreenData'); // print('filterData :- $filterData'); isLoading = false; }); // print('chartsData -$chartsData'); // print('cardData -$cardData'); } void applyFilters(BuildContext context, List filters, List data, List dataCard, List selectedFilters) { setState(() { isLoading = true; }); Navigator.pop(context); print('applyFilters called'); print('Selected ApplyFilters: $selectedFilters'); if (selectedFilters.every((filter) => filter['filter_data'].isEmpty)) { setState(() { chartsData = List.from(originalTabChartsData); // Restore the original data // cardData = List.from(originalTabCardData); // Restore the original data }); print('Returning as no filters are selected'); Navigator.pop(context); return; // Exit early since all filter_data are empty } // Transform the selectedFilters list into the required format formattedFilters = selectedFilters // .where((filter) => filter['filter_data'] != null && filter['filter_data'].isNotEmpty) .map((filter) { return { 'filter_key': filter['filter_key'], 'filter_data': filter['filter_data'].map((item) => item.toString()).toList() }; }).toList(); print('Formatted Filters1: $formattedFilters'); // Convert to JSON format String selectedFormatFilters = jsonEncode({'kpi': tabWiseKpi, 'filter_data': formattedFilters}); print('Formatted Filters2: $selectedFormatFilters'); final locale = ref.watch(localeProvider)?.languageCode ?? 'en'; print('locale2- $locale'); // Call fetchChartData with correct parameters fetchChartData( widget.dataSets, locale, tabWiseKpi, // Ensure you are passing the correct KPI here formattedFilters // Pass the formatted filter data here ); // Navigator.pop(context); selectedFiltersStorage = List.from(selectedFilters); print('selectedFiltersStoraged- $selectedFiltersStorage'); } void applyFilters1(BuildContext context, List filters, List data, List dataCard, List selectedFilters) { print("applyFilters called"); print("Selected ApplyFilters: $selectedFilters"); print("Selected data: $data"); if (selectedFilters.every((filter) => filter['filter_data'].isEmpty)) { setState(() { chartsData = List.from(originalTabChartsData); // Restore the original data // cardData = List.from(originalTabCardData); // Restore the original data }); print('Returning as no filters are selected'); Navigator.pop(context); return; // Exit early since all filter_data are empty } // Loop through each chart data in the `data` list List filteredData = []; Set addedChartIds = {}; // Track unique chart identifiers for (var chart in data) { final groupBy = chart['group_by']; List response = chart['response'] ?? []; final chartHeading = chart['chart_heading']; // Filter the response based on selected filters var chartFilteredData = response.where((responseItem) { final obsKey = responseItem['ObsKey']; // Check if each selected filter's `filter_data` matches `ObsKey` values return selectedFilters.every((filter) { final filterKey = filter['filter_key']; final filterValues = filter['filter_data']; // Ensure the filter_key exists in the `ObsKey` and check if it matches any of the `filter_data` if (groupBy == filterKey && obsKey.containsKey(filterKey)) { final obsKeyValue = obsKey[filterKey]?.toString(); return filterValues.isEmpty || filterValues.contains(obsKeyValue); } if (filterKey == 'TIME_PERIOD' && obsKey.containsKey('TIME_PERIOD')) { final timePeriodValue = obsKey['TIME_PERIOD']?.toString(); return filterValues.isEmpty || filterValues.contains(timePeriodValue); } return true; }); }).toList(); print('chartFilteredData- $chartFilteredData'); // If chartFilteredData is empty, print the message if (chartFilteredData.isEmpty) { if (kDebugMode) { print( "Selected year: ${selectedFilters.firstWhere((f) => f['filter_key'] == 'TIME_PERIOD', orElse: () => { 'filter_data': ['Unknown'] })['filter_data']} - No data for chart: : $chartHeading"); } // Add the complete chart data to the filteredData list filteredData.add({ ...chart, 'response': response, // Return full unfiltered response }); continue; } // If any data matches the filter, add the whole chart data object // Add filtered chart only once if (chartFilteredData.isNotEmpty && !addedChartIds.contains(chart['chart_heading'])) { filteredData.add({ ...chart, 'response': chartFilteredData, }); addedChartIds .add(chart['chart_heading']); // Track by a unique identifier } } // List filteredCardData = []; // for (var chart in dataCard) { // Map chartData = Map.from(chart); // // Extract response data for filtering // List response = chartData['response'] ?? []; // // Filter the response based on selected filters // var cardFilteredData = response.where((responseItem) { // final obsKey = responseItem['ObsKey']; // // Check if each selected filter's `filter_data` matches `ObsKey` values // return selectedFilters.every((filter) { // final filterKey = filter['filter_key']; // final filterValues = filter['filter_data']; // // Ensure the filter_key exists in the `ObsKey` and check if it matches any of the `filter_data` // if (obsKey.containsKey(filterKey)) { // final obsKeyValue = obsKey[filterKey]?.toString(); // return filterValues.isEmpty || filterValues.contains(obsKeyValue); // } // return false; // }); // }).toList(); // // // If any data matches the filter, add the whole chart data object // if (cardFilteredData.isNotEmpty) { // filteredCardData.add({ // ...chart, // Include all other properties of the chart object // 'response': cardFilteredData, // Only include filtered response data // }); // } // } // Update the chartsData with the filtered data setState(() { chartsData = filteredData; // cardData = filteredCardData; // Adjust this part as needed }); print("Filtered Data: $filteredData"); // print("Filtered Card: $filteredCardData"); // Go back after applying filters Navigator.pop(context); } String capitalizeAndSplit(String text) { if (text.isEmpty) return text; return text .split('_') // Split by underscores .map((word) => word[0].toUpperCase() + word.substring(1).toLowerCase()) .join(' '); // Join words with a space } void showRightSideModal(BuildContext context, List filters, List data) { // Hide system UI (including bottom navigation bar) SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); print('selectedFiltersStoraged1- $selectedFiltersStorage'); // Initialize selected filters structure from the stored value, if exists List> selectedFilters = selectedFiltersStorage.isNotEmpty ? List.from(selectedFiltersStorage) // Use stored filters : filters.map((filter) { return {"filter_key": filter["filter_key"], "filter_data": []}; }).toList(); // Or initialize empty filters print('selectedFiltersStoragedrgt- $selectedFiltersStorage'); showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (BuildContext context) { return Align( alignment: Alignment.centerRight, child: Container( width: MediaQuery.of(context).size.width * 0.7, height: MediaQuery.of(context).size.height, color: Colors.white, child: Column( children: [ // Header Section Padding( padding: const EdgeInsets.only( top: 26.0, bottom: 0.0, left: 16.0, right: 16.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ SvgPicture.asset( UaeNumbersAssetPath.filterCharts, semanticsLabel: 'Filter', colorFilter: ColorFilter.mode( Color(0xFF8E8E8E), BlendMode.srcIn), width: 25, height: 25, ), SizedBox(width: 8), Text( context.translate( 'Filters', 'المرشحات', ), style: TextStyle( color: Color(0xFF8E8E8E), fontSize: 20, fontWeight: FontWeight.w500, fontFamily: context.translate( 'Roboto', 'NotoKufi', ), ), ), ], ), // IconButton( // icon: Icon(Icons.close), // onPressed: () => Navigator.pop(context), // ), ], ), ), // Filters Section Divider( color: Color(0xFFA7B5C5), ), Expanded( child: ListView.builder( itemCount: filters.length, itemBuilder: (context, index) { filters.sort((a, b) => a["filter_text_and_order"]["order"] .compareTo(b["filter_text_and_order"]["order"])); final filter = filters[index]; final filterKey = filter["filter_key"]; final filterData = filter["filter_data"]; final filter_text_and_order = filter["filter_text_and_order"]; final fieldOrder = filter_text_and_order['order']; return StatefulBuilder( builder: (context, setState) { // Get the corresponding selected filter object var selectedFilter = selectedFilters .firstWhere((f) => f["filter_key"] == filterKey); return Padding( padding: const EdgeInsets.symmetric( horizontal: 16.0, vertical: 8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( context.translate(filter_text_and_order['en'], filter_text_and_order['ar']), // capitalizeAndSplit(filterKey), style: TextStyle( fontSize: 16, fontWeight: FontWeight.w700, fontFamily: context.translate( 'Roboto', 'NotoKufi', ), color: Color(0xFF8E8E8E), ), ), InkWell( onTap: () { showDialog( context: context, builder: (BuildContext context) { return StatefulBuilder( builder: (context, dialogSetState) { final locale = ref.watch(localeProvider); print('localelocale $locale'); return AlertDialog( title: Text( // "${locale == 'ar' ? 'يختار ' : 'Select '}" "${context.translate(filter_text_and_order['en'], filter_text_and_order['ar'])}", style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ) ),), content: SingleChildScrollView( child: ListBody( children: filterData .map((value) { return CheckboxListTile( title: Text( value.toString(), style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ) ),), value: selectedFilter[ "filter_data"] .contains(value), onChanged: (bool? isChecked) { dialogSetState(() { if (isChecked == true) { selectedFilter[ "filter_data"] .add(value); } else { selectedFilter[ "filter_data"] .remove(value); } }); }, ); }).toList(), ), ), actions: [ TextButton( onPressed: () { // Store the updated selected filters after dialog closes setState(() {}); Navigator.pop(context); }, child: Text( context.translate( 'OK', 'نعم', ), style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ) ), ), ), ], ); }, ); }, ); }, child: Container( width: double.infinity, padding: EdgeInsets.symmetric( horizontal: 16.0, vertical: 12.0), decoration: BoxDecoration( border: Border.all(color: Color(0xFF7296BE)), borderRadius: BorderRadius.circular(8.0), ), child: Wrap( spacing: 8.0, runSpacing: 4.0, children: selectedFilter["filter_data"].isEmpty ? [ Text( // "${locale == 'ar' ? 'يختار ' : 'Select '}" "${context.translate(filter_text_and_order['en'], filter_text_and_order['ar'])}", style: TextStyle( color: Colors.grey, fontFamily: context.translate( 'Roboto', 'NotoKufi', ),), ) ] : selectedFilter["filter_data"] .map((value) { return Chip( label: Text(value, style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ) ),), // backgroundColor: Colors.white, // Default background color onDeleted: () { setState(() { selectedFilter[ "filter_data"] .remove(value); }); }, ); }).toList(), ), ), ), ], ), ); }, ); }, ), ), Padding( padding: const EdgeInsets.all(16.0), child: Row( children: [ Expanded( child: ElevatedButton( onPressed: () { setState(() { isLoading = true; }); selectedFilters.forEach((filter) { filter["filter_data"].clear(); }); setState(() { chartsData = List.from(originalTabChartsData); cardData = List.from(originalTabCardData); }); selectedFiltersStorage.clear(); formattedFilters = []; final locale = ref.watch(localeProvider)?.languageCode ?? 'en'; print('locale22- $locale'); fetchChartData( widget.dataSets, locale, tabWiseKpi, // Ensure you are passing the correct KPI here formattedFilters // Pass the formatted filter data here ); Navigator.pop(context); }, style: ElevatedButton.styleFrom( backgroundColor: Color(0xFF92722A), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: Padding( padding: const EdgeInsets.symmetric( horizontal: 0.0, vertical: 14.2), // Added padding child: Text( context.translate('Clear', 'واضح'), style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), color: Colors.white, fontSize: 13, fontWeight: FontWeight.bold, ), overflow: TextOverflow.ellipsis, // Prevents wrapping maxLines: 1, // Ensures single line ), ), ), ), SizedBox(width: 16), Expanded( child: ElevatedButton( onPressed: () { print( "Selected Filters before applying: $selectedFilters"); if (selectedFilters.every((filter) => filter['filter_data'].isEmpty)) { setState(() { isLoading = true; }); selectedFilters.forEach((filter) { filter["filter_data"].clear(); }); setState(() { chartsData = List.from(originalTabChartsData); cardData = List.from(originalTabCardData); }); selectedFiltersStorage.clear(); formattedFilters = []; final locale = ref.watch(localeProvider)?.languageCode ?? 'en'; print('locale22- $locale'); fetchChartData( widget.dataSets, locale, tabWiseKpi, // Ensure you are passing the correct KPI here formattedFilters // Pass the formatted filter data here ); Navigator.pop(context); } else { setState(() { // isLoading = true; chartsData = originalTabChartsData; cardData = originalTabCardData; }); applyFilters(context, filters, chartsData, cardData, selectedFilters); // selectedFiltersStorage = List.from(selectedFilters); } }, style: ElevatedButton.styleFrom( backgroundColor: Color(0xFF92722A), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: Padding( padding: const EdgeInsets.symmetric( horizontal: 0.0, vertical: 14.2), // Added padding child: FittedBox( fit: BoxFit .scaleDown, // Ensures text resizes if necessary child: Text( context.translate('Filter', 'فلتر'), style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), color: Colors.white, fontSize: 13, fontWeight: FontWeight.bold, ), overflow: TextOverflow.ellipsis, // Prevents wrapping maxLines: 1, // Ensures single line ), ), ), ), ), ], ), ), ], ), ), ); }, ).whenComplete(() { // Restore system UI when modal is dismissed SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); }); } void onTabSelected(String tabId) { print('Selected Tab on: $tabId'); tabWiseKpi = tabId; print('Selected Tab tabWiseKpi: $tabWiseKpi'); selectedFiltersStorage.clear(); if (selectedFiltersApi.isNotEmpty && tabWiseKpi == tabFilteredKpi) { selectedFiltersStorage = List.from(selectedFiltersApi); } filterData = filterDataSet .where((item) => item['key'] == tabId) .map((item) => item['value']) .where((item) => item != null && item is Iterable) .expand((item) => item) .toList(); print("FilteringDAtss START1d - $filterData"); print('TABId1 - $tabId'); Map monthMap = { 'jan': 1, 'feb': 2, 'mar': 3, 'apr': 4, 'may': 5, 'jun': 6, 'jul': 7, 'aug': 8, 'sep': 9, 'oct': 10, 'nov': 11, 'dec': 12 }; for (var item in filterData) { if (item['filter_key'] == 'TIME_PERIOD') { List timePeriods = List.from(item['filter_data']); timePeriods.sort((a, b) { List aParts = a.split(RegExp(r'[-_]')); List bParts = b.split(RegExp(r'[-_]')); int yearA = int.parse(aParts[0]); int yearB = int.parse(bParts[0]); // if (yearA != yearB) return yearA.compareTo(yearB); if (yearA != yearB) return yearB.compareTo(yearA); // Sort years in descending order if (aParts.length == 1) return -1; // Year-only comes first if (bParts.length == 1) return 1; // Year-only comes first int monthA = int.tryParse(aParts[1]) ?? monthMap[aParts[1].toLowerCase()] ?? 0; int monthB = int.tryParse(bParts[1]) ?? monthMap[bParts[1].toLowerCase()] ?? 0; return monthB.compareTo( monthA); // Sort months in descending order within the same year // return monthA.compareTo(monthB); }); item['filter_data'] = timePeriods; } else if (item['filter_key'] == 'REF_AREA') { continue; } else { // Sort alphabetically for all other cases List otherFilters = List.from(item['filter_data']); otherFilters.sort((a, b) => a.toLowerCase().compareTo(b.toLowerCase())); item['filter_data'] = otherFilters; } } // for (var item in filterData) { // if (item['filter_key'] == 'TIME_PERIOD') { // // Convert the values to integers, sort them, and convert back to strings // List timePeriodData = item['filter_data'] // .map((e) => int.parse(e.toString())) // Convert to int // .toList(); // timePeriodData.sort((a, b) => a.compareTo(b)); // Sort numerically // // // Optionally, convert sorted integers back to strings if necessary // item['filter_data'] = timePeriodData.map((e) => e.toString()).toList(); // } // } print('TABId - $tabId'); print("TABFiltered Data: $filterData"); setState(() { chartsData = originalChartsData; cardData = originalCardData; }); performActionForTab(tabId); } void performActionForTab(String tabId) { print('Selected Tab perform: $tabId'); // Filter the chartsData array based on the tabId tabFilteredChartData = chartsData.where((chart) { // Assuming each chart item has a 'kpi' field that matches tabId return chart['kpi'] == tabId; }).toList(); // Convert to list after filtering print('tabFilteredChartData Data for Tab $tabId: $tabFilteredChartData'); setState(() { chartsData = tabFilteredChartData; originalTabChartsData = List.from(tabFilteredChartData); // Store original data }); // Filter the chartsData array based on the tabId tabFilteredCardData = cardData.where((chart) { // Assuming each chart item has a 'kpi' field that matches tabId return chart['kpi'] == tabId; }).toList(); // Convert to list after filtering print( 'tabFilteredCardData Data for Tab before $tabId: $tabFilteredCardData'); tabFilteredCardData .sort((a, b) => (a['order_id'] as int).compareTo(b['order_id'] as int)); print( 'tabFilteredCardData Data for Tab after $tabId: $tabFilteredCardData'); setState(() { cardData = tabFilteredCardData; originalTabCardData = List.from(tabFilteredCardData); }); // You can perform further actions with the filteredData, like updating the UI // For example, you can update the chart data or display the results } // double calculateAspectRatio(int itemCount) { // // Modify the logic based on your layout requirements // if (itemCount <= 2) { // return 190.5 / 180; // } else if (itemCount == 3) { // return 180.0 / 250; // } else if (itemCount == 4) { // return 190.5 / 180; // } else { // return 180.0 / 180; // Default for more items // // return 190.5 / 180; // } // } double calculateAspectRatio(int crossAxisCount, List cardData) { // Determine a default aspect ratio based on the most common chart type in the list if (cardData.any((item) => item['chart_type'] == 'total' || item['chart_type'] == 'average')) { // return crossAxisCount == 1 ? 0.2 : (crossAxisCount > 2 ? 0.9 : 0.7); return crossAxisCount == 2 ? 1.0 : 0.7; // Larger Content // return crossAxisCount == 2 ? 1.5 : 0.9; } else { return crossAxisCount == 2 ? 1.5 : 0.9; // Shorter Content } } Future shareCurrentPage(BuildContext context, bool isSharing) async { if (isSharing) return; // Prevent multiple taps isSharing = true; setState(() { isLoading = true; }); try { final String currentRoute = GoRouterState.of(context).uri.toString(); final String baseAppLink = 'https://fcscapp.onelink.me'; final String shareLink = '$baseAppLink$currentRoute'; final String shareText = 'Check this out!\n\n$shareLink'; print('Generated Share Link: $shareLink'); // Optional: Capture SVG to image final String svgAssetPath = 'assets/backgrounds/share/fcsc.svg'; final screenshotController = ScreenshotController(); final svgWidget = SvgPicture.asset( svgAssetPath, width: 200, height: 200, ); final Uint8List? capturedImage = await screenshotController.captureFromWidget( Material(child: svgWidget), ); if (capturedImage == null) { print('SVG capture failed, proceeding without image.'); await Share.share(shareText, subject: 'App Link'); } else { final directory = await getTemporaryDirectory(); final file = File('${directory.path}/share_image.png'); await file.writeAsBytes(capturedImage); await Share.shareXFiles( [XFile(file.path)], text: shareText, subject: 'Shared Content', ); await file.delete(); } setState(() { isLoading = false; }); } catch (e) { setState(() { isLoading = false; }); print("Error sharing content: $e"); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Error sharing: ${e.toString()}')), ); } finally { setState(() { isLoading = false; }); isSharing = false; // Reset flag } } // double calculateAspectRatio(int crossAxisCount, List cardData) { // if (cardData.any((item) => // item['chart_type'] == 'total' || item['chart_type'] == 'average')) { // if (crossAxisCount == 1) { // return 0.9 ; // Aspect ratio when crossAxisCount is less than 2 // } else if (crossAxisCount == 2) { // return 1.0; // Aspect ratio when crossAxisCount is exactly 2 // } else if (crossAxisCount > 2) { // return 1.0; // Aspect ratio when crossAxisCount is greater than 2 // } // } else { // if (crossAxisCount < 2) { // return 0.8; // Aspect ratio when crossAxisCount is less than 2 // } else if (crossAxisCount == 2) { // return 1.5; // Aspect ratio when crossAxisCount is exactly 2 // } else if (crossAxisCount > 2) { // return 0.9; // Aspect ratio when crossAxisCount is greater than 2 // } // } // return 1.0; // Default fallback (should never be reached) // } @override Widget build(BuildContext context) { final locale = ref.watch(localeProvider); final localeNotifier = ref.read(localeProvider.notifier); String url=GoRouterState.of(context).uri.toString(); final uri = Uri.parse(url); final pageTitle = uri.queryParameters['key'] ?? ''; final isConnected = ref.watch(connectivityProvider); // If no internet, redirect to InternetCheckScreen ref.listen>(connectivityProvider, (previous, hasInternet) { if (hasInternet.value == false) { context.push('/internetcheck'); } }); ref.listen(localeProvider, (previous, next) async { final localeCode = next?.languageCode ?? 'en'; // Default to 'en' if null setState(() { isLoading = true; print('isLoadingref $isLoading'); }); await _userService.updateLanguage(localeCode); // fetchChartData(widget.dataSets, localeCode); print('Saving currentTab: $tabWiseKpi before locale change'); print('localeCodeWgt- $localeCode'); currentTab = tabWiseKpi; print('Saving currentTab: $currentTab After locale change'); final List> safeFilterData = widget.filter_data ?? []; final String safeKpi = widget.kpi ?? ''; fetchChartData(widget.dataSets, localeCode, safeKpi, safeFilterData) .then((_) { print('DEBUG KPI: $safeKpi'); print('TAB11: $currentTab'); if (currentTab.isNotEmpty) { // Call onTabSelected for the first tab onTabSelected(currentTab); print('TAB1: $currentTab'); } else if (_tabsData.isNotEmpty) { // Call onTabSelected for the first tab print('TAB2: $_tabsData'); onTabSelected(_tabsData[0]['id']); } }); }); double myheight = MediaQuery.of(context).size.height; double mywidth = MediaQuery.of(context).size.width; mainTopic = chartScreenData['main_topic'] ?? ''; int crossAxisCount = cardData.isNotEmpty ? (cardData.length / 2).ceil().clamp(1, 2) : 1; final color = Color(int.parse(widget.bgColor.replaceFirst('0x', ''), radix: 16)); // Color bodyColor = Color( // int.parse( // (chartScreenData['body_color'] ?? '#898C81') // .replaceFirst('#', '0xFF'), // Correct format for ARGB in Flutter // radix: 16, // ), // ); // // final bodyColor = Color( int.parse( (chartScreenData['body_color'] ?? '#898C81').replaceFirst('#', '0xff'), ), ); final chartHeader = chartScreenData['main_topic'] ?? ''; print('ChartScrnBodyColor'); print('chartHeader - $chartHeader'); print(chartScreenData['body_color']); print( Color(int.parse((chartScreenData['body_color'] ?? '#898C81') .replaceFirst('#', '0xff'))), ); return PopScope( canPop: false, // Allow back navigation only if not login screen onPopInvokedWithResult: (didPop, result) { if (didPop) return; context.pop(); // context.go('/uaenumbers'); // Show exit confirmation dialog }, child: BaseScaffold( key: _scaffoldKey, title: (pageTitle == 'home') ? Text(AppLocalizations.of(context)!.nav_home, style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ) ),) : Text( context.translate( 'UAE Numbers', 'أرقام الإمارات', ), style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ) ), ), // appbarColor: Color(int.parse(widget.bgColor)), // Example color appbarColor: Color(int.parse( (chartScreenData['header_color'] ?? '#ffffff') .replaceFirst('#', '0xff'))), // Example color showBackButton: true, colorChange: true, navBackArrow: Text(widget.keyParam ?? 'Default Value'), body: Stack(children: [ if (!isLoading) Container( color: color, child: Column( children: [ Container( // height: myheight / 5, width: double.infinity, // color: color, color: Color(int.parse( (chartScreenData['header_color'] ?? '#898C81') .replaceFirst('#', '0xff'))), child: Padding( padding: EdgeInsets.only( left: 30, right: 30, top: 8, bottom: 5), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( // widget.mainTopic ?? '', // chartScreenData['main_topic'] ?? '', mainTopic, style: TextStyle( color: Colors.white, fontSize: 28, fontWeight: FontWeight.w600, fontFamily: context.translate( 'Roboto', 'NotoKufi', ), ), ), Container( width: mywidth / 7, height: 1.5, child: Divider( thickness: 4, color: Colors.white, )), Text( // widget.title, chartScreenData['data_set_tile_heading'] ?? '', style: TextStyle( color: Colors.white, fontSize: 20, fontWeight: FontWeight.w500, fontFamily: context.translate( 'Roboto', 'NotoKufi', ), ), ), ], ), )), Container( color: Color(int.parse( (chartScreenData['header_color'] ?? '#898C81') .replaceFirst('#', '0xff'))), child: Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Row( mainAxisAlignment: MainAxisAlignment.end, children: [ Row( key: bookMarkKey, children: [ GestureDetector( onTap: () { if (isBookmarked) { showRemoveBookmarkDialog(); } else { showAddBookmarkDialog(); } }, child: Container( padding: EdgeInsets.all(4), decoration: BoxDecoration( color: isBookmarked ? Colors.white.withAlpha(90) : null, // Background color borderRadius: BorderRadius.circular( 8), // Curved corners ), child: Row( children: [ isBookmarked ? Text( context.translate( 'Bookmarked', 'إشارة مرجعية', ), style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), fontSize: 16, color: Color(int.parse( (chartScreenData[ 'body_color'] ?? '#898C81') .replaceFirst( '#', '0xff'))), ), ) : Text( context.translate( 'Bookmark', 'إشارة مرجعية', ), style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), fontSize: 16, color: Colors.white, ), ), SizedBox(width: 5), // Text( // "Bookmark", // style: const TextStyle( // fontSize: 16, // color: Colors.white), // ), // const SizedBox(width: 5), // Image.asset( // isBookmarked // ? UaeNumbersAssetPath // .bookmarksSelectedUae // Filled bookmark image // : UaeNumbersAssetPath // .bookmarksUae, // Default bookmark image // // color: Colors.white, // width: 24, // height: 24, // ), Icon( size: 24, Icons.bookmarks_rounded, color: isBookmarked ? Color(int.parse( (chartScreenData[ 'body_color'] ?? '#898C81') .replaceFirst( '#', '0xff'))) : Colors.white, ), ], ), ), ), ], ), SizedBox(width: 10), Row( children: [ GestureDetector( onTap: () => shareCurrentPage(context, _isSharing), child: Row( children: [ Text( context.translate('Share', 'يشارك'), style:TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), fontSize: 16, color: Colors.white, ), ), SizedBox(width: 5), _isSharing ? SizedBox( width: 24, height: 24, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2, ), ) // Show loading spinner : SvgPicture.asset( UaeNumbersAssetPath.share, semanticsLabel: 'share', width: 24, height: 24, ), ], ), ), ], ), SizedBox( width: 10), // Horizontal space between items Row( children: [ GestureDetector( onTap: () { showRightSideModal( context, filterData, chartsData); }, child: Row( children: [ Text( context.translate( 'Filter', 'فلتر', ), style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), fontSize: 16, color: Colors.white, ), ), SizedBox(width: 10), SvgPicture.asset( UaeNumbersAssetPath.filterCharts, semanticsLabel: 'Filter', width: 24, height: 24, ), ], ), ) // IconButton( // icon: Icon(Icons.filter_alt_outlined, // color: Colors.white, size: 24), // onPressed: () { // showRightSideModal( // context, filterData, chartsData); // }, // ), ], ), SizedBox(width: 10), ], ), ], ), ), Expanded( child: Container( color: Color(int.parse( (chartScreenData['body_color'] ?? '#898C81') .replaceFirst('#', '0xff'))), child: Padding( padding: const EdgeInsets.all(10.0), child: ListView( children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ // Left arrow button if (_tabsData.length > 1) _buildArrowButton( onPressed: _activeTabIndex > 0 ? _scrollLeft : null, icon: Icons.arrow_back_ios_new, ), // Tabs with horizontal scroll if (_tabsData.length > 1) Expanded( child: SingleChildScrollView( controller: _scrollController, scrollDirection: Axis.horizontal, child: Row( children: List.generate( _tabsData.length, (index) { return _buildTab( _tabsData[index], isActive: index == _activeTabIndex, ); }), ), ), ), // Right arrow button if (_tabsData.length > 1) _buildArrowButton( onPressed: _activeTabIndex < _tabsData.length - 1 ? _scrollRight : null, icon: Icons.arrow_forward_ios, ), ], ), // Expanded( // child: Center( // child: Text( // 'Selected Tab: ${_tabsData.isNotEmpty ? _tabsData[_activeTabIndex] : 'None'}', // style: const TextStyle(fontSize: 18), // ), // ), // ), // nonChartData Cards Padding( padding: const EdgeInsets.only( top: 8.0, left: 1.0, right: 1.0), child: LayoutBuilder( key: cardKey, builder: (context, constraints) { List rows = []; List tempRow = []; for (var card in cardData) { if (card['card_full_length'] == true) { if (tempRow.isNotEmpty) { rows.add(Row(children: tempRow)); tempRow = []; } rows.add(Row( children: [ Expanded( child: CardWidget( card: card, chartScreenData: chartScreenData)), ], )); } else { tempRow.add(Expanded( child: CardWidget( card: card, chartScreenData: chartScreenData))); if (tempRow.length == 2) { rows.add(Row(children: tempRow)); tempRow = []; } } } if (tempRow.isNotEmpty) { rows.add(Row(children: tempRow)); } return SingleChildScrollView( child: Column( children: rows, ), ); }, ), ), ListView.builder( itemCount: chartsData.length, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) { return Card( margin: const EdgeInsets.all(10), child: Container( decoration: BoxDecoration( border: Border.all( color: Color( int.parse( (chartScreenData[ 'border_color'] ?? '#898C81') .replaceFirst('#', '0xff'), ), ), // Border color width: 1, // Border width ), color: Colors.white, borderRadius: BorderRadius.circular( 8), // Optional: Rounded corners ), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // ConstrainedBox Container( height: (chartsData[index][ 'chart_height'] == null || chartsData[index][ 'chart_height'] == 0) ? 350 : double.tryParse( chartsData[index] ['chart_height'] .toString()), // height: (chartsData[index] // ['chart_type'] == // 'pie_chart') // ? 500 // : (chartsData[index][ // 'chart_type'] == // 'bar_chart_horizontal') // ? 370 // : (chartsData[index][ // 'chart_type'] == // 'horizontal_rotate') // ? 385 // : (chartsData[index] // [ // 'chart_type'] == // 'fl_stacked_bar') // ? 390 // : 350, // child: buildChart(chartsData[index]), child: ChartWidget( chartData: chartsData[index], bodyColor: bodyColor, chartHeader: chartHeader), ) ], ), ), )); }, ), ], ), ), ), ), ], ), ), if (isLoading) Container( color: Color(0x98FFFCE5), // Semi-transparent background child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( margin: EdgeInsets.symmetric( horizontal: 40), // Left & Right space child: LinearProgressIndicator( minHeight: 5, // Adjust thickness backgroundColor: Colors.grey[100], // Optional: Background color valueColor: AlwaysStoppedAnimation( Color(0xFFAA8E83)), // Loader color ), ), ], ), ) ])), ); } Widget _buildArrowButton( {required VoidCallback? onPressed, required IconData icon}) { final color = Color(int.parse(widget.bgColor.replaceFirst('0x', ''), radix: 16)); return Container( margin: EdgeInsets.symmetric(horizontal: 5.0), width: 30.0, // Set the width of the circle height: 30.0, decoration: BoxDecoration( color: onPressed == null ? Colors.grey[400] : Colors.white, shape: BoxShape.circle, // boxShadow: [ // BoxShadow( // color: Colors.black26, // blurRadius: 4.0, // offset: Offset(2, 2), // ), // ], ), child: IconButton( onPressed: onPressed, icon: Icon(icon, color: onPressed == null ? Colors.grey : color), iconSize: 15.0, ), ); } Widget _buildTab(Map tab, {bool isActive = false}) { return GestureDetector( onTap: () { setState(() { _activeTabIndex = _tabsData.indexOf(tab); }); _scrollToIndex(_activeTabIndex); onTabSelected(tab['id']!); }, child: Container( margin: EdgeInsets.symmetric(horizontal: 8.0), padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 16.0), decoration: BoxDecoration( color: isActive ? Colors.white : Colors.grey[400], borderRadius: BorderRadius.circular(20.0), ), child: Text( tab['name']!, style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), color: isActive ? Colors.black : Colors.white, fontWeight: isActive ? FontWeight.w500 : FontWeight.w400, fontSize: 13, ), ), ), ); } } // Function to convert hex color string to Color Color _getColorFromHex(String hexColor) { hexColor = hexColor.replaceFirst('#', ''); if (hexColor.length == 6) { hexColor = 'FF$hexColor'; // Add alpha if not provided } return Color(int.parse(hexColor, radix: 16)); } class CardWidget extends StatelessWidget { final Map card; final Map chartScreenData; const CardWidget( {Key? key, required this.card, required this.chartScreenData}) : super(key: key); @override Widget build(BuildContext context) { final chart_type = card['chart_type']; final chart_heading = card['chart_heading']; final card_full_length = card['card_full_length']; print('cardfulllength $card_full_length'); final response = card['response'] as List? ?? []; final card_logo = card['card_logo']; double cardHeight = (chart_type == 'totals' || chart_type == 'averages') ? 180.0 : 130.0; final bodyColor = Color( int.parse( (chartScreenData['border_color'] ?? '#898C81') .replaceFirst('#', '0xff'), ), ); if (response.isEmpty) { return SizedBox.shrink(); } else if (response.length == 1) { return Container( margin: const EdgeInsets.all(10), // width: card_full_length ? double.infinity : null, decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all( color: Color(int.parse( (chartScreenData['border_color'] ?? '#898C81') .replaceFirst('#', '0xff'))), // Dynamic border color width: 1, // Adjust border thickness ), ), child: Card( margin: const EdgeInsets.all(0), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), elevation: 2, child: Container( // height: cardHeight, height: 158 , padding: const EdgeInsets.only( left: 16.0, right: 16.0, bottom: 2.0, top: 1.0), decoration: BoxDecoration( color: Colors.white, // Move color inside BoxDecoration borderRadius: BorderRadius.circular( 12), // Ensure border radius is applied ), child: Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ Image.network( card_logo ?? '', width: 30, height: 30, errorBuilder: (context, error, stackTrace) { return Icon(Icons.public, color: Color(0xFF90B0D5), size: 30); // Fallback icon }, ), const SizedBox(height: 1), MouseRegion( onEnter: (event) { // Show tooltip on hover final overlay = Overlay.of(context) .context .findRenderObject() as RenderBox; final entry = OverlayEntry( builder: (context) => Positioned( left: overlay.localToGlobal(Offset.zero).dx, top: overlay.localToGlobal(Offset.zero).dy, child: Material( color: Colors.transparent, child: Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.black87, borderRadius: BorderRadius.circular(4), ), child: Text( chart_heading ?? 'NA', style: TextStyle(color: Colors.white, fontFamily: context.translate( 'Roboto', 'NotoKufi', ),), ), ), ), ), ); Overlay.of(context).insert(entry); Future.delayed( Duration(seconds: 2), () => entry.remove()); }, child: Text( chart_heading ?? 'NA', textAlign: TextAlign.center, maxLines: 2, overflow: TextOverflow.ellipsis, // Truncate text with '...' style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), fontSize: 11, fontWeight: FontWeight.w400, color: Colors.black87, ), ), ), const SizedBox(height: 5), Text( RegExp(r'\d').hasMatch(response[0]['display_value'] ?? '') ? '(${response[0]['display_value'] ?? 'NA'})' : '${response[0]['display_value'] ?? 'NA'}', style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), fontSize: 11, color: Colors.grey, overflow: TextOverflow.ellipsis, // Truncate if text overflows ), maxLines: 1, // Limit to one line to prevent overflow textAlign: TextAlign.center, // Ensure proper alignment ), const SizedBox(height: 1), Row( mainAxisAlignment: MainAxisAlignment .center, // Center-aligns the row contents children: [ Text( response[0]['value'] ?? 'NA', textAlign: TextAlign.center, // Ensures text is centered style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), fontSize: 23, fontWeight: FontWeight.w800, color: (response[0]['font_color'] ?? '').isEmpty ? bodyColor : _getColorFromHex(response[0]['font_color']), ), ), const SizedBox(width: 4), // Space between text and icon if (response[0]['font_color'] != '') ...[ if (response[0]['font_color'] == '#D83731') const Icon(Icons.arrow_downward, color: Colors.red, size: 20) else if (response[0]['font_color'] == '#11AF22') const Icon(Icons.arrow_upward, color: Colors.green, size: 20), ], ], ) ], ), ), )); } else { return Container( margin: const EdgeInsets.all(10), // width: card_full_length ? double.infinity : null, decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all( color: Color(int.parse( (chartScreenData['border_color'] ?? '#898C81') .replaceFirst('#', '0xff'))), // Dynamic border color width: 1, // Adjust border thickness ), ), child: Card( margin: const EdgeInsets.all(0), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), elevation: 0, // Remove shadow to keep only the outli child: Container( height: 158, padding: const EdgeInsets.all(10.0), // padding: const EdgeInsets.only( // left: 10.0, right: 10.0, bottom: 5.0, top: 1.0), decoration: BoxDecoration( color: Colors.white, // Move color inside BoxDecoration borderRadius: BorderRadius.circular(12), // Ensure border radius is applied ), child: Column( mainAxisSize: MainAxisSize.min, // Adjust card height based on content mainAxisAlignment: MainAxisAlignment.center, children: [ // const Icon(Icons.public, // color: Color(0xFF90B0D5), size: 30), Image.network( card_logo ?? '', width: 30, height: 30, errorBuilder: (context, error, stackTrace) { return Icon(Icons.public, color: Color(0xFF90B0D5), size: 30); // Fallback icon }, ), const SizedBox(height: 3), MouseRegion( onEnter: (event) { final overlay = Overlay.of(context); final entry = OverlayEntry( builder: (context) => Positioned( left: event.position.dx, top: event.position.dy + 10, // Adjust tooltip position child: Material( color: Colors.transparent, child: Container( padding: EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.black87, borderRadius: BorderRadius.circular(4), ), child: Text( chart_heading ?? 'NA', style: TextStyle(color: Colors.white, fontSize: 10, fontFamily: context.translate( 'Roboto', 'NotoKufi', ),), ), ), ), ), ); overlay.insert(entry); Future.delayed(Duration(seconds: 2), () => entry.remove()); }, child: SizedBox( width: double.infinity, // Ensures it uses available space child: Text( chart_heading ?? 'NA', textAlign: TextAlign.center, maxLines: 2, overflow: TextOverflow.ellipsis, // Truncate with '...' style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), fontSize: 11, fontWeight: FontWeight.w400, color: Colors.black87, ), ), ), ), const SizedBox(height: 1), Text( // '(${response[0]['display_value'] ?? 'NA'})', RegExp(r'\d').hasMatch(response[0]['display_value'] ?? '') ? '(${response[0]['display_value'] ?? 'NA'})' : '${response[0]['display_value'] ?? 'NA'}', style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), fontSize: 11, color: Colors.grey, overflow: TextOverflow.ellipsis, ), ), const SizedBox(height: 1), Row( mainAxisAlignment: MainAxisAlignment .center, // Center-aligns the row contents children: [ Text( response[0]['value'] ?? 'NA', overflow: TextOverflow.ellipsis, maxLines: 1, style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), fontSize: 23, fontWeight: FontWeight.w900, color: (response[0]['font_color'] ?? '').isEmpty ? bodyColor : _getColorFromHex(response[0]['font_color']), ), ), const SizedBox(width: 1), // Space between text and icon if (response[0]['font_color'] != '') ...[ if (response[0]['font_color'] == '#D83731') const Icon(Icons.arrow_downward, color: Colors.red, size: 20) else if (response[0]['font_color'] == '#11AF22') const Icon(Icons.arrow_upward, color: Colors.green, size: 20), ], ], ), SizedBox( height: 2, // Height of the divider width: 100, child: Divider( color: Color(0xFFBBBCBD), thickness: 1, // Divider line thickness ), ), Row( mainAxisAlignment: MainAxisAlignment .center, // Center-aligns the row contents children: [ Text( response[1]['value'] ?? 'NA', style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), fontSize: 16, fontWeight: FontWeight.w600, color: (response[1]['font_color'] ?? '').isEmpty ? const Color(0xFFD83731) : _getColorFromHex(response[1]['font_color']), ), textAlign: TextAlign.center, // Ensure proper alignment overflow: TextOverflow.ellipsis, // Truncate if text overflows ), const SizedBox(width: 1), // Space between text and icon if (response[1]['font_color'] != '') ...[ if (response[1]['font_color'] == '#D83731') const Icon(Icons.arrow_downward, color: Colors.red, size: 20) else if (response[1]['font_color'] == '#11AF22') const Icon(Icons.arrow_upward, color: Colors.green, size: 20), ], ], ), Text( // '(${response[1]['display_value'] ?? 'NA'})', RegExp(r'\d').hasMatch(response[1]['display_value'] ?? '') ? '(${response[1]['display_value'] ?? 'NA'})' : '${response[1]['display_value'] ?? 'NA'}', style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), fontSize: 8, fontWeight: FontWeight.w500, color: Colors.grey, overflow: TextOverflow.ellipsis, ), ), ], ), ), ), ); } // return Card( // elevation: 4, // shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), // child: Padding( // padding: const EdgeInsets.all(16.0), // child: Column( // crossAxisAlignment: CrossAxisAlignment.start, // children: [ // Image.network( // card['card_logo'], // height: 50, // width: 50, // fit: BoxFit.contain, // ), // SizedBox(height: 10), // Text( // card['chart_heading'] ?? '', // style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), // ), // SizedBox(height: 10), // Column( // crossAxisAlignment: CrossAxisAlignment.start, // children: List.generate(card['response'].length, (index) { // var response = card['response'][index]; // return Text( // "${response['display_value']}: ${response['value']}", // style: TextStyle(fontSize: 14), // ); // }), // ), // ], // ), // ), // ); } }