uaestats_fe/lib/presentation/Screens/charts/screens/chart_screen.dart
2025-06-13 15:43:37 +05:30

3395 lines
139 KiB
Dart

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<Map<String, dynamic>> 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<ChartScreen1> createState() => _ChartScreen1State();
}
class _ChartScreen1State extends ConsumerState<ChartScreen1> {
// final _pb = PocketBase('https://pb.venbait.in');
final _pb = PocketBase(apiUrl);
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
final ApiService apiService = ApiService();
bool isLoading = true;
bool _isSharing = false;
List<dynamic> isChartData = [];
List<dynamic> nonChartData = [];
Map<String, dynamic> chartScreenData = {};
List<dynamic> filterDataSet = [];
List<dynamic> filterData = [];
List<dynamic> chartsData = [];
List<dynamic> tabFilteredChartData = [];
List<dynamic> tabFilteredCardData = [];
List<dynamic> cardData = [];
List<Map<String, dynamic>> filteredAndSortedData = [];
List<Map<String, dynamic>> selectedFiltersStorage = [];
List<Map<String, dynamic>> selectedFiltersApi = [];
List<dynamic> originalChartsData = [];
List<dynamic> originalCardData = [];
List<dynamic> originalTabCardData = [];
List<dynamic> originalTabChartsData = [];
late Color backgroundColor;
final ScrollController _scrollController = ScrollController();
int _activeTabIndex = 0;
dynamic tabWiseKpi = [];
dynamic tabFilteredKpi = [];
List<Map<String, dynamic>> formattedFilters = [];
dynamic _tabsData = [];
dynamic currentTab = [];
// List<Map<String, dynamic>> _tabsData = [];
late List<TargetFocus> marriageTargets;
late List<TargetFocus> 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<void> 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<void> 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<void> 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<double?> _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<void> 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<void> _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<void> _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<String, List<Map<String, dynamic>>> 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<Map<String, String>> _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<String, List<Map<String, dynamic>>> 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<Map<String, String>> _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<void> 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<Map<String, dynamic>>((entry) {
if (entry is Map<dynamic, dynamic>) {
return entry.map<String, dynamic>(
(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<String> 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<String, dynamic> chartData = Map<String, dynamic>.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<Map<String, dynamic>> 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<Widget>((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<Widget>((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<String, int> 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<String> timePeriods = List<String>.from(item['filter_data']);
timePeriods.sort((a, b) {
List<String> aParts = a.split(RegExp(r'[-_]'));
List<String> 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<String> otherFilters = List<String>.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<int> timePeriodData = item['filter_data']
// .map<int>((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<dynamic> 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<void> 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<dynamic> 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<AsyncValue<bool>>(connectivityProvider, (previous, hasInternet) {
if (hasInternet.value == false) {
context.push('/internetcheck');
}
});
ref.listen<Locale?>(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<Map<String, dynamic>> 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<Widget> rows = [];
List<Widget> 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>(
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<String, String> 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<String, dynamic> card;
final Map<String, dynamic> 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<dynamic>? ?? [];
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),
// );
// }),
// ),
// ],
// ),
// ),
// );
}
}