diff --git a/.run/main.dart.run.xml b/.run/main.dart.run.xml index 4a58a7c9..4767aff8 100644 --- a/.run/main.dart.run.xml +++ b/.run/main.dart.run.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/assets/app_tour/down_right.png b/assets/app_tour/down_right.png new file mode 100644 index 00000000..be10a1bb Binary files /dev/null and b/assets/app_tour/down_right.png differ diff --git a/assets/app_tour/leftDown.png b/assets/app_tour/leftDown.png new file mode 100644 index 00000000..4ba2314e Binary files /dev/null and b/assets/app_tour/leftDown.png differ diff --git a/assets/app_tour/leftUp.png b/assets/app_tour/leftUp.png new file mode 100644 index 00000000..56df6adc Binary files /dev/null and b/assets/app_tour/leftUp.png differ diff --git a/lib/l10n/intl_ar.arb b/lib/l10n/intl_ar.arb index a191b63e..1f5eb600 100644 --- a/lib/l10n/intl_ar.arb +++ b/lib/l10n/intl_ar.arb @@ -82,5 +82,13 @@ "password_between_8_to_40": "يجب أن تتراوح كلمة المرور بين 8 و64 حرفًا", "new_password_required": "كلمة المرور الجديدة مطلوبة", "old_password_is_required": "كلمة المرور القديمة مطلوبة", - "confirm_password_is_required": "تأكيد كلمة المرور مطلوب" + "confirm_password_is_required": "تأكيد كلمة المرور مطلوب", + + "kpiCards": "يمكنك عرض بطاقات مؤشرات الأداء الرئيسية التفاعلية والرسوم البيانية لاستكشاف اتجاهات البيانات ومقارنة المقاييس الرئيسية بصريًا", + "home_topic": "اختر أي فئة (على سيبل المثال : الاقتصاد، الاجتماعية، البيئة) لاستكشاف مؤشرات الأداء الرئيسية التفصيلية ، التصورات، ورؤى البيانات .", + "economy": "يمكنك الوصول إلى الإحصائيات التفصيلية وصفحات التحليل لمؤشرات الأداء الرئيسية في فئة الاقتصاد لاكتشاف الاتجاهات والمقاييس الرئيسية .", + "bookMark": "يمكنك وضع إشارة مرجعية على مؤشرات الأداء الرئيسية أو مجموعات البيانات المهمة للوصول السريع والسهل في أي وقت من خلال قسم الإشارات المرجعية. ", + "toggle": "يمكنك التبديل بين اللغتين الإنجليزية والعربية باستخدام مفتاح تبديل اللغة في الزاوية اليمنى العليا للحصول على تجربة ثنائية اللغة.", + "tour_navBar": "يمكنك استخدام شريط التنقل للوصول السريع إلى الملف الشخصي ,التعليقات , دليل المستخدم , الإشعارات والميزات الأساسية الأخرى للتطبيق.", + "mainMenu": "يمكنك الوصول إلى الصفحات المخصصة والميزات الإضافية عن طريق تحديد الخيارات من القائمة الرئيسية." } \ No newline at end of file diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index b034d44b..dac0f961 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -13,7 +13,7 @@ "enter_your_password": "Enter your password", "register_Confirm_password": "Confirm password", "agree": "I agree to ", - "t_and": "and", + "t_and": " and ", "conditions": " of Fcsc", "terms_conditions": "terms & conditions", "privacy_policy":"privacy policy", @@ -83,5 +83,13 @@ "password_between_8_to_40": "Password must be between 8 and 64 characters", "new_password_required": "New password is required", "old_password_is_required": "Old password is required", - "confirm_password_is_required": "Confirm password is required" + "confirm_password_is_required": "Confirm password is required", + + "kpiCards": "View interactive KPI cards and graphs to explore data trends and compare key metrics visually.", + "home_topic": "Tap on any category (e.g., Economy, Social, Environment) to explore detailed KPIs, visualizations, and data insights.", + "economy": "Access detailed statistics and drill-down pages for KPIs in the Economy category to uncover key trends and metrics.", + "bookMark": "Bookmark important KPIs or datasets for quick and easy access anytime through the Bookmarks section.", + "toggle": "Switch between English and Arabic using the language toggle at the top-right corner for a bilingual experience.", + "tour_navBar": "Use the navigation bar to quickly access Profile, Feedback, User Guide, Notifications, and other key app features.", + "mainMenu": "Access dedicated pages and additional features by selecting options from the Main Menu." } diff --git a/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/Social/marriages.dart b/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/Social/marriages.dart index 0a9a7e50..c4541382 100644 --- a/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/Social/marriages.dart +++ b/lib/presentation/Screens/Bottom Navigation Pages/UAE_Numbers/Social/marriages.dart @@ -1,12 +1,626 @@ import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:go_router/go_router.dart'; +import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; import 'package:uae_stat/presentation/components/constant/constant.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:uae_stat/presentation/Screens/app_tour/Target_content.dart'; - -class Marriages extends StatelessWidget { +class Marriages extends ConsumerStatefulWidget { const Marriages({super.key}); + @override + ConsumerState createState() => _MarriagesState(); +} + +class _MarriagesState extends ConsumerState { + late List marriageTargets; + late List previousMarriageTargets; + late TutorialCoachMark tutorialCoachMark; + final GlobalKey chartKey = GlobalKey(); + final GlobalKey bookMarkKey = GlobalKey(); + late double cardHeight= 0; + + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) { + _calculateMarkPosition(); + _startTutorialAfterRender(); + }); + } + + void handleSkip() { + tutorialCoachMark.skip(); + debugPrint('Skip clicked'); + 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'); + } + + void _kpiTutorialCoachMark() { + + + _initmarriageTargets(); + tutorialCoachMark = TutorialCoachMark( + paddingFocus: 0, + useSafeArea: true, + pulseEnable: false, + hideSkip: true, + targets: marriageTargets, + onClickTarget: (target) { + if (target.identify == 'chartKey') { + // Scroll to the long widget + Scrollable.ensureVisible( + chartKey.currentContext!, + duration: Duration(milliseconds: 500), + ); + } + }, + onFinish: () { + context.push('/myhomepage'); + debugPrint('Marriage Tutorial Finished'); + }, + + )..show(context: context); + + } + void _previousKpiTutorial() { + + _initpreviousTargets(); + tutorialCoachMark = TutorialCoachMark( + paddingFocus: 0, + useSafeArea: true, + pulseEnable: false, + hideSkip: true, + targets: previousMarriageTargets, + onFinish: () { + context.push('/myhomepage'); + debugPrint('Previous Marriage Tutorial Finished'); + }, + + )..show(context: context); + + } + + + void _startTutorialAfterRender() { + final chartTour = ref.watch(chartsTourProvider); + final previousChartTour = ref.watch(previousChartsTourProvider); + if (chartKey.currentContext != null && !chartTour) { + _kpiTutorialCoachMark(); + } else if(!previousChartTour) { + _previousKpiTutorial(); + } + else if (!chartTour || !previousChartTour){ + Future.delayed(Duration(milliseconds: 100), _startTutorialAfterRender); + }else{ + return; + } + + } + + void _calculateMarkPosition() { + final RenderBox cardRenderBox = bookMarkKey.currentContext!.findRenderObject() as RenderBox; + final Size cardSize = cardRenderBox.size; + cardHeight = cardSize.height; + debugPrint('height : $cardHeight'); + } + + void _initmarriageTargets(){ + final double screenWidth= MediaQuery.of(context).size.width; + final double screenHeight= MediaQuery.of(context).size.height; + marriageTargets=[ + TargetFocus( + identify: 'chartsKey', + keyTarget: chartKey, + shape: ShapeLightFocus.RRect, + contents: [ + createTargetContent( + text: AppLocalizations.of(context)!.kpiCards, + alignment: ContentAlign.top, + gap:50, + space: 0, + ), + TargetContent( + align: ContentAlign.bottom, + child: SizedBox( + width: double.infinity, + height: MediaQuery.of(context).size.height*0.3, + child: Stack( + children: [ + Positioned( + bottom: 25, + left: 16, + right: 16, + child: 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: const Text( + 'Skip', + style: TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + ), + Column( + children: [ + Text( + '3/7', + style: const TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + const SizedBox(height: 3), + Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: Colors.white, width: 2.0), + ), + child: IconButton( + iconSize: 20, + icon: const Icon(Icons.arrow_back, color: Colors.white), + onPressed: () { + 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: Color(0xFF7DAFBC), + border: Border.all(color: Color(0xFF7DAFBC), width: 1.5), + ), + child: IconButton( + iconSize: 20, + icon: const Icon(Icons.arrow_forward, color: Colors.white), + onPressed: () { + 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( + identify: 'BookMarkKey', + keyTarget: bookMarkKey, + shape: ShapeLightFocus.RRect, + contents: [ + createTargetContent( + text: AppLocalizations.of(context)!.bookMark, + alignment: ContentAlign.bottom, + gap: 23, + space: 50, + ), + TargetContent( + align: ContentAlign.bottom, + child: SizedBox( + width: double.infinity, + height: MediaQuery.of(context).size.height*0.60, + child: Stack( + children: [ + Positioned( + bottom: 35, + left: 16, + right: 16, + child: 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: const Text( + 'Skip', + style: TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + ), + Column( + children: [ + Text( + '4/7', + style: const TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + const SizedBox(height: 3), + Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: Colors.white, width: 2.0), + ), + child: IconButton( + iconSize: 20, + icon: const Icon(Icons.arrow_back, color: Colors.white), + onPressed: () { + tutorialCoachMark.previous(); + }, + ), + ), + const SizedBox(width: 10), + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Color(0xFF7DAFBC), + border: Border.all(color: Color(0xFF7DAFBC), width: 1), + ), + child: IconButton( + iconSize: 20, + icon: const Icon(Icons.arrow_forward, color: Colors.white), + onPressed: () { + ref.read(chartsTourProvider.notifier).state=true; + ref.read(scaffoldTourProvider.notifier).state=false; + tutorialCoachMark.finish(); + }, + ), + ), + ], + ), + ], + ), + ], + ), + ), + ], + ), + ), + ), + TargetContent( + padding: EdgeInsets.only(left:0, top: cardHeight+20), + align: ContentAlign.right, + child: Container( + width: screenWidth/4, + height: screenHeight, + child: Stack( + children: [ + Image.asset( + 'assets/app_tour/leftDown.png', + fit: BoxFit.contain, + ), + // Positioned( + // top: 0, + // left: MediaQuery.of(context).size.width* 0.5, + // child: SizedBox( + // width: 50, + // height: 100, + // child: Image.asset( + // 'assets/app_tour/bookmark2.png', + // fit: BoxFit.contain, + // ), + // ), + // ), + ], + ), + ), + ), + ], + ), + ]; + } + + void _initpreviousTargets(){ + final double screenWidth= MediaQuery.of(context).size.width; + final double screenHeight= MediaQuery.of(context).size.height; + previousMarriageTargets=[ + TargetFocus( + identify: 'BookMarkKey', + keyTarget: bookMarkKey, + shape: ShapeLightFocus.RRect, + contents: [ + createTargetContent( + text: AppLocalizations.of(context)!.bookMark, + space: 50, + alignment: ContentAlign.bottom, + gap: 23, + ), + TargetContent( + align: ContentAlign.bottom, + child: SizedBox( + width: double.infinity, + height: MediaQuery.of(context).size.height*0.60, + child: Stack( + children: [ + Positioned( + bottom: 35, + left: 16, + right: 16, + child: 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: const Text( + 'Skip', + style: TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + ), + Column( + children: [ + Text( + '4/7', + style: const TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + const SizedBox(height: 3), + Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: Colors.white, width: 2.0), + ), + child: IconButton( + iconSize: 20, + icon: const Icon(Icons.arrow_back, color: Colors.white), + onPressed: () { + tutorialCoachMark.next(); + }, + ), + ), + const SizedBox(width: 10), + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Color(0xFF7DAFBC), + border: Border.all(color:Color(0xFF7DAFBC), width: 1.5), + ), + child: IconButton( + iconSize: 20, + icon: const Icon(Icons.arrow_forward, color: Colors.white), + onPressed: () { + ref.read(chartsTourProvider.notifier).state=true; + ref.read(scaffoldTourProvider.notifier).state=false; + tutorialCoachMark.finish(); + }, + ), + ), + ], + ), + ], + ), + ], + ), + ), + ], + ), + ), + ), + TargetContent( + padding: EdgeInsets.only(left:0, top: cardHeight+20), + align: ContentAlign.right, + child: Container( + width: screenWidth/4, + height: screenHeight, + child: Stack( + children: [ + Image.asset( + 'assets/app_tour/leftDown.png', + fit: BoxFit.contain, + ), + // Positioned( + // top: 0, + // left: MediaQuery.of(context).size.width* 0.5, + // child: SizedBox( + // width: 50, + // height: 100, + // child: Image.asset( + // 'assets/app_tour/bookmark2.png', + // fit: BoxFit.contain, + // ), + // ), + // ), + ], + ), + ), + ), + ], + ), + TargetFocus( + identify: 'chartsKey', + keyTarget: chartKey, + shape: ShapeLightFocus.RRect, + contents: [ + createTargetContent( + text: AppLocalizations.of(context)!.kpiCards, + space: 0, + alignment: ContentAlign.top, + gap:50, + ), + TargetContent( + align: ContentAlign.bottom, + child: SizedBox( + width: double.infinity, + height: MediaQuery.of(context).size.height*0.3, + child: Stack( + children: [ + Positioned( + bottom: 30, + left: 16, + right: 16, + child: 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: const Text( + 'Skip', + style: TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + ), + Column( + children: [ + Text( + '3/7', + style: const TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + const SizedBox(height: 3), + Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: Colors.white, width: 2.0), + ), + child: IconButton( + iconSize: 20, + icon: const Icon(Icons.arrow_back, color: Colors.white), + onPressed: () { + 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: Color(0xFF7DAFBC), + border: Border.all(color:Color(0xFF7DAFBC), width: 1.5), + ), + child: IconButton( + iconSize: 20, + icon: const Icon(Icons.arrow_forward, color: Colors.white), + onPressed: () { + 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, + ), + ), + ] + ), + + ), + ), + ], + ), + + + ]; + } @override Widget build(BuildContext context) { double myheight = MediaQuery.of(context).size.height; @@ -33,7 +647,7 @@ class Marriages extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - IconButton(onPressed: (){}, icon: Icon(Icons.bookmark_add_outlined,color: Colors.white,size: 40,)), + IconButton(key :bookMarkKey,onPressed: (){}, icon: Icon(Icons.bookmark_add_outlined,color: Colors.white,size: 40,)), IconButton(onPressed: (){}, icon: Icon(Icons.share,color: Colors.white,size: 30,)), ],), ], @@ -47,6 +661,7 @@ class Marriages extends StatelessWidget { child: Column( children: [ Row( + key:chartKey, mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Container(height: myheight/3.5,width: mywidth/2.5, diff --git a/lib/presentation/Screens/app_tour/Target_content.dart b/lib/presentation/Screens/app_tour/Target_content.dart new file mode 100644 index 00000000..51e52b06 --- /dev/null +++ b/lib/presentation/Screens/app_tour/Target_content.dart @@ -0,0 +1,50 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; +import 'package:flutter/material.dart'; + +final allTargetsCompletedProvider = StateProvider((ref) => true); +final chartsTourProvider = StateProvider((ref) => true); +final previousChartsTourProvider = StateProvider((ref) => true); +final homeTourProvider = StateProvider((ref) => false); +final previousHomeTourProvider = StateProvider((ref) => true); +final scaffoldTourProvider = StateProvider((ref) => true); +final previousScaffoldTourProvider = StateProvider((ref) => true); + +TargetContent createTargetContent({ + required String text, + required ContentAlign alignment, + required double gap, + required double space , +}) { + return TargetContent( + align: alignment, + builder: (context, controller) { + return Stack( + children: [ + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + padding: EdgeInsets.only(left: 10, right: 10, bottom: space , top: space ), + decoration: BoxDecoration( + color: Colors.transparent, + borderRadius: BorderRadius.circular(12), + ), + child: Text( + text, + style: const TextStyle( + color: Colors.white, + fontSize: 18, + ), + textAlign: TextAlign.center, + ), + ), + SizedBox(height: gap,), + ], + ), + ], + ); + }, + ); +} \ No newline at end of file diff --git a/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart b/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart index 4c41728f..ab7cc0f0 100644 --- a/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart +++ b/lib/presentation/routes/bottom_bar_routes/tab_routes/home_route.dart @@ -166,7 +166,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; -import '../../drawer_routes/custom_drawer_routes.dart'; +import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; +import 'package:uae_stat/presentation/Screens/app_tour/Target_content.dart'; +import 'package:uae_stat/presentation/routes/drawer_routes/custom_drawer_routes.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:http/http.dart' as http; @@ -205,11 +208,556 @@ class EconomyStatsState extends ConsumerState { bool isLoading = true; + final GlobalKey cardTopicKey = GlobalKey(); + final GlobalKey cardsKey = GlobalKey(); + late TutorialCoachMark tutorialCoachMark; + late List homeTargets; + late List previousHomeTargets; + Offset _imageCardPosition =Offset.zero; + Offset _imageTopicPosition =Offset.zero; + + void _calculateCardPosition() { + final RenderBox cardRenderBox = cardsKey.currentContext!.findRenderObject() as RenderBox; + final Offset cardPosition = cardRenderBox.localToGlobal(Offset.zero); + final Size cardSize = cardRenderBox.size; + + // Calculate the position for the image + final double imageX = cardPosition.dx + cardSize.width / 2; + final double imageY = cardPosition.dy + cardSize.height; + + setState(() { + _imageCardPosition = Offset(imageX, imageY); + }); + } + + void handleSkip() { + tutorialCoachMark.skip(); + debugPrint('Skip clicked'); + 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; + } + + //Method waits app tour to render Targets + void _starTourRender() { + if (cardTopicKey.currentContext != null) { + _showHomeTour(); + } else { + Future.delayed(Duration(milliseconds: 100), _starTourRender); + } + } + + //Method to Start App Tour + void _showHomeTour() { + final homeTour = ref.watch(homeTourProvider); + final previousHomeTour = ref.watch(previousHomeTourProvider); + +// Check and show tutorials + if (!homeTour) { + // Show Home Tour + _initTarget(); + _calculateCardPosition(); + tutorialCoachMark = TutorialCoachMark( + paddingFocus: 0, + useSafeArea: true, + pulseEnable: false, + hideSkip: true, + targets: homeTargets, + onFinish: () { + ref.read(homeTourProvider.notifier).state = true; + ref.read(chartsTourProvider.notifier).state = false; + debugPrint('Home Tutorial Finished'); + context.push('/marriages'); + }, + )..show(context: context); + } else if (!previousHomeTour) { + _initPreviousTarget(); + tutorialCoachMark = TutorialCoachMark( + paddingFocus: 0, + useSafeArea: true, + pulseEnable: false, + hideSkip: true, + targets: previousHomeTargets, + onFinish: () { + ref.read(previousHomeTourProvider.notifier).state = true; + debugPrint('Previous Home Tutorial Finished'); + context.push('/marriages'); + }, + )..show(context: context); + } + + } + + void _initTarget(){ + homeTargets=[ + TargetFocus( + identify: 'cardTopicKey', + keyTarget: cardTopicKey, + shape: ShapeLightFocus.RRect, + contents: [ + createTargetContent( + text: AppLocalizations.of(context)!.home_topic, + alignment: ContentAlign.bottom, + gap: 45, + space: 40, + ), + TargetContent( + align: ContentAlign.bottom, + child: SizedBox( + width: double.infinity, + height: MediaQuery.of(context).size.height*0.69, + child: Stack( + children: [ + Positioned( + bottom: 35, + left: 16, + right: 16, + child: 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: const Text( + 'Skip', + style: TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + ), + Column( + children: [ + Text( + '1/7', + style: const TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + const SizedBox(height: 3), + Row( + children: [ + const SizedBox(width: 10), + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Color(0xFF7DAFBC), + border: Border.all(color: Color(0xFF7DAFBC), width: 1), + ), + child: IconButton( + padding: EdgeInsets.zero, + iconSize: 20, + icon: const Icon(Icons.arrow_forward, color: Colors.white), + onPressed: () { + tutorialCoachMark.next(); + }, + ), + ), + ], + ), + ], + ), + ], + ), + ), + ], + ), + ), + ), + TargetContent( + align: ContentAlign.bottom, + 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.4, + top: _imageCardPosition.dy-29, + child: Image.asset( + 'assets/app_tour/down_right.png', + width: 40, + height: 90, + ), + ), + ] + ), + + ), + ), + ], + ), + TargetFocus( + identify: 'cardsKey', + keyTarget: cardsKey, + shape: ShapeLightFocus.RRect, + contents: [ + createTargetContent( + text:AppLocalizations.of(context)!.economy, + alignment: ContentAlign.bottom, + gap: 0, + space: 40,), + + TargetContent( + align: ContentAlign.bottom, + child: + SizedBox( + width: double.infinity, + height: MediaQuery.of(context).size.height *0.5, // Set an appropriate height for the Stack + child: Stack( + children: [ + Positioned( + bottom: 25, + left: 16, + right: 16, + child: 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: const Text( + 'Skip', + style: TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + ), + Column( + children: [ + Text( + '2/7', + style: const TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + const SizedBox(height: 3), + Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: Colors.white, width: 2.0), + ), + child: IconButton( + iconSize: 20, + icon: const Icon(Icons.arrow_back, color: Colors.white), + onPressed: () { + tutorialCoachMark.previous(); + }, + ), + ), + const SizedBox(width: 10), + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Color(0xFF7DAFBC), + border: Border.all(color: Color(0xFF7DAFBC), width: 1), + ), + child: IconButton( + iconSize: 20, + icon: const Icon(Icons.arrow_forward, color: Colors.white), + onPressed: () { + tutorialCoachMark.next(); + }, + ), + ), + ], + ), + ], + ), + ], + ), + ), + ], + ), + ), + ), + TargetContent( + align: ContentAlign.bottom, + 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, + top: _imageTopicPosition.dy-29, + child: Image.asset( + 'assets/app_tour/down_right.png', + width: 40, + height: 90, + ), + ), + ] + ), + + ), + ), + ], + ), + ]; + } + + void _initPreviousTarget(){ + previousHomeTargets=[ + TargetFocus( + identify: 'cardsKey', + keyTarget: cardsKey, + shape: ShapeLightFocus.RRect, + contents: [ + createTargetContent( + text:AppLocalizations.of(context)!.economy, + alignment: ContentAlign.bottom, + gap: 0, + space: 40,), + TargetContent( + align: ContentAlign.bottom, + child: + SizedBox( + width: double.infinity, + height: MediaQuery.of(context).size.height *0.5, // Set an appropriate height for the Stack + child: Stack( + children: [ + Positioned( + bottom: 25, + left: 16, + right: 16, + child: 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: const Text( + 'Skip', + style: TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + ), + Column( + children: [ + Text( + '2/7', + style: const TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + const SizedBox(height: 3), + Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: Colors.white, width: 2.0), + ), + child: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.white), + onPressed: () { + tutorialCoachMark.next(); + }, + ), + ), + const SizedBox(width: 10), + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Color(0xFF7DAFBC), + border: Border.all(color: Color(0xFF7DAFBC), width: 1.5), + ), + child: IconButton( + iconSize: 20, + icon: const Icon(Icons.arrow_forward, color: Colors.white), + onPressed: () { + ref.read(previousHomeTourProvider.notifier).state=true; + ref.read(chartsTourProvider.notifier).state=false; + tutorialCoachMark.finish(); + }, + ), + ), + ], + ), + ], + ), + ], + ), + ), + ], + ), + ), + ), + TargetContent( + align: ContentAlign.bottom, + 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, + top: _imageTopicPosition.dy-29, + child: Image.asset( + 'assets/app_tour/down_right.png', + width: 40, + height: 90, + ), + ), + ] + ), + + ), + ), + ], + ), + TargetFocus( + identify: 'cardTopicKey', + keyTarget: cardTopicKey, + shape: ShapeLightFocus.RRect, + contents: [ + createTargetContent( + text:AppLocalizations.of(context)!.home_topic, + alignment: ContentAlign.bottom, + gap: 45, + space: 40, + ), + TargetContent( + align: ContentAlign.bottom, + child: SizedBox( + width: double.infinity, + height: MediaQuery.of(context).size.height*0.69, + child: Stack( + children: [ + Positioned( + bottom: 35, + left: 16, + right: 16, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + ElevatedButton( + onPressed: () { + tutorialCoachMark.skip(); + debugPrint('Skip clicked'); + }, + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + side: const BorderSide(color: Colors.white), + backgroundColor: Colors.transparent, + elevation: 0, + ), + child: const Text( + 'Skip', + style: TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + ), + Column( + children: [ + Text( + '1/7', + style: const TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + const SizedBox(height: 3), + Row( + children: [ + const SizedBox(width: 10), + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Color(0xFF7DAFBC), + border: Border.all(color: Color(0xFF7DAFBC), width: 1.5), + ), + child: IconButton( + iconSize: 20, + icon: const Icon(Icons.arrow_forward, color: Colors.white), + onPressed: () { + tutorialCoachMark.previous(); + }, + ), + ), + ], + ), + ], + ), + ], + ), + ), + ], + ), + ), + ), + TargetContent( + align: ContentAlign.bottom, + 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.4, + top: _imageCardPosition.dy-29, + child: Image.asset( + 'assets/app_tour/down_right.png', + width: 40, + height: 90, + ), + ), + ] + ), + + ), + ), + ], + ), + ]; + } + + @override void initState() { super.initState(); final locale = ref.read(localeProvider); fetchData(locale?.languageCode ?? 'en'); + WidgetsBinding.instance.addPostFrameCallback((_) { + _starTourRender(); + }); } // @override @@ -327,6 +875,9 @@ class EconomyStatsState extends ConsumerState { crossAxisAlignment: CrossAxisAlignment.start, children: [ RoundedCornerContainer( + key: mainTopic['main_topic'] =='ECONOMY' + ? cardTopicKey + : null, text: mainTopic['main_topic'], backgroundColor: backgroundColor, textStyle: const TextStyle( @@ -338,6 +889,9 @@ class EconomyStatsState extends ConsumerState { SizedBox( height: myheight / 4.8, // Set dynamic height child: Container( + key:mainTopic['main_topic'] == 'ECONOMY' + ? cardsKey + : null, // color: Colors.grey[200], // Set a background color for the scrollable container child: ConstrainedBox( constraints: BoxConstraints( diff --git a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart index 6f5472c0..82073e8d 100644 --- a/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart +++ b/lib/presentation/routes/drawer_routes/custom_drawer_routes.dart @@ -9,7 +9,11 @@ import 'package:package_info_plus/package_info_plus.dart'; import 'package:pocketbase/pocketbase.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; +import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; +import 'package:uae_stat/presentation/components/my_toggle.dart'; +import 'package:uae_stat/presentation/Screens/app_tour/Target_content.dart'; import 'package:uae_stat/presentation/components/indicators/locale_provider.dart'; import 'package:uae_stat/presentation/components/my_toggle.dart'; @@ -50,12 +54,448 @@ class _BaseScaffoldState extends ConsumerState { String? collectionIds; String? collectionId; + late TutorialCoachMark tutorialCoachMark; + late List appBarTargets; + final GlobalKey bottomNavKey = GlobalKey(); + final GlobalKey toggleKey = GlobalKey(); + final GlobalKey drawerKey = GlobalKey(); + late double toggleHeight=0; bool isLoggedOut = false; @override void initState() { super.initState(); _checkUserId(); + WidgetsBinding.instance.addPostFrameCallback((_) { + _startAppbarTour(); + }); + } + //Method to Start App Tour + void _startAppbarTour() { + final scaffoldProvider = ref.watch(scaffoldTourProvider); + _calculatetooglePosition(); + if (!scaffoldProvider) { + // Show Home Tour + _initTarget(); + tutorialCoachMark = TutorialCoachMark( + paddingFocus: 0, + useSafeArea: true, + pulseEnable: false, + hideSkip: true, + targets: appBarTargets, // Ensure `homeTargets` is defined for Home Tour + onFinish: () { + ref.read(homeTourProvider.notifier).state = true; + debugPrint('Home Tutorial Finished'); + }, + )..show(context: context); + } + + } + + void _calculatetooglePosition() { + final RenderBox cardRenderBox = toggleKey.currentContext!.findRenderObject() as RenderBox; + final Offset cardPosition = cardRenderBox.localToGlobal(Offset.zero); + final Size cardSize = cardRenderBox.size; + toggleHeight = cardSize.height; + } + + void handleSkip() { + tutorialCoachMark.skip(); + debugPrint('Skip clicked'); + 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; + } + + void _initTarget(){ + final double screenWidth= MediaQuery.of(context).size.width; + final double screenHeight= MediaQuery.of(context).size.height; + appBarTargets=[ + TargetFocus( + identify: 'bottomNav', + keyTarget: bottomNavKey, + shape: ShapeLightFocus.RRect, // Rounded rectangle highlight + contents: [ + createTargetContent( + text: AppLocalizations.of(context)!.tour_navBar, + alignment: ContentAlign.top, + space: 0, + gap: 100, + + ), + TargetContent( + align: ContentAlign.top, + child: + SizedBox( + width: double.infinity, + height: MediaQuery.of(context).size.height* 0.30, // Set an appropriate height for the Stack + child: Stack( + children: [ + Positioned( + bottom: 25, + left: 16, + right: 16, + child: 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: const Text( + 'Skip', + style: TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + ), + Column( + children: [ + Text( + '5/7', + style: const TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + const SizedBox(height: 3), + Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: Colors.white, width: 2.0), + ), + child: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.white), + onPressed: () { + tutorialCoachMark.finish(); + ref.read(scaffoldTourProvider.notifier).state=true; + ref.read(previousChartsTourProvider.notifier).state=false; + context.push('/marriages'); + }, + ), + ), + const SizedBox(width: 10), + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Color(0xFF7DAFBC), + border: Border.all(color: Color(0xFF7DAFBC), width: 1.5), + ), + child: IconButton( + icon: const Icon(Icons.arrow_forward, color: Colors.white), + onPressed: () { + tutorialCoachMark.next(); + }, + ), + ), + ], + ), + ], + ), + ], + ), + ), + ], + ), + ), + ), + TargetContent( + padding: EdgeInsets.only(left:screenWidth*0.4, bottom: 0 ), + align: ContentAlign.top, + child: Container( + width: 200, + height: 100, + child: Stack( + children: [ + Image.asset( + 'assets/app_tour/leftUp.png', + fit: BoxFit.contain, + ), + + ], + ), + ), + ), + ], + ), + TargetFocus( + identify: 'drawerKey', + keyTarget: drawerKey, + shape: ShapeLightFocus.RRect, + radius: 0, // No rounded corners + paddingFocus: 1, // Rounded rectangle highlight + contents: [ + createTargetContent( + text: AppLocalizations.of(context)!.mainMenu, + alignment: ContentAlign.bottom, + gap: 55, + space: 0, + ), + TargetContent( + align: ContentAlign.bottom, + child: + SizedBox( + width: double.infinity, + height: MediaQuery.of(context).size.height* 0.80, // Set an appropriate height for the Stack + child: Stack( + children: [ + Positioned( + bottom: 25, + left: 16, + right: 16, + child: 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: const Text( + 'Skip', + style: TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + ), + Column( + children: [ + Text( + '6/7', + style: const TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + const SizedBox(height: 3), + Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: Colors.white, width: 2.0), + ), + child: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.white), + onPressed: () { + tutorialCoachMark.previous(); + }, + ), + ), + const SizedBox(width: 10), + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Color(0xFF7DAFBC), + border: Border.all(color: Color(0xFF7DAFBC), width: 1), + ), + child: IconButton( + icon: const Icon(Icons.arrow_forward, color: Colors.white), + onPressed: () { + tutorialCoachMark.next(); + }, + ), + ), + ], + ), + ], + ), + ], + ), + ), + ], + ), + ), + ), + TargetContent( + padding: EdgeInsets.only(right: screenWidth*0.7, top: toggleHeight-5), + align: ContentAlign.right, + child: Container( + width: 200, + height: screenHeight/4, + child: Stack( + children: [ + Image.asset( + 'assets/app_tour/leftDown.png', + fit: BoxFit.contain, + ), + // Positioned( + // top: 0, + // left: MediaQuery.of(context).size.width* 0.5, + // child: SizedBox( + // width: 50, + // height: 100, + // child: Image.asset( + // 'assets/app_tour/bookmark2.png', + // fit: BoxFit.contain, + // ), + // ), + // ), + ], + ), + ), + ), + ], + ), + TargetFocus( + identify: 'toggleKey', + keyTarget: toggleKey, + shape: ShapeLightFocus.RRect, + radius: 0, + paddingFocus: 0,// Rounded rectangle highlight + contents: [ + createTargetContent( + text: AppLocalizations.of(context)!.toggle, + space: 0, + alignment: ContentAlign.bottom, + gap: 50, + ), + TargetContent( + align: ContentAlign.bottom, + child: + SizedBox( + width: double.infinity, + height: MediaQuery.of(context).size.height* 0.80, + child: Stack( + children: [ + Positioned( + bottom: 25, + left: 16, + right: 16, + child: 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: const Text( + 'Skip', + style: TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + ), + Column( + children: [ + Text( + '7/7', + style: const TextStyle( + color: Colors.white, + fontSize: 14, + ), + ), + const SizedBox(height: 3), + Row( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all(color: Colors.white, width: 2.0), + ), + child: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.white), + onPressed: () { + tutorialCoachMark.previous(); + }, + ), + ), + const SizedBox(width: 10), + + ElevatedButton( + onPressed: () { + debugPrint('Got it clicked'); + 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; + tutorialCoachMark.finish(); + }, + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + side: const BorderSide(color: Colors.white), + backgroundColor: Colors.white, + elevation: 0, + ), + child: const Text( + 'Got it', + style: TextStyle( + color: Color(0xFF7DAFBC), + fontSize: 14, + ), + ), + ), + ], + ), + ], + ), + ], + ), + ), + ], + ), + ), + ), + TargetContent( + padding: EdgeInsets.only(left:screenWidth*0.7, top: toggleHeight), + align: ContentAlign.left, + child: Container( + width: 200, + height: screenHeight/4, + child: Stack( + children: [ + Image.asset( + 'assets/app_tour/down_right.png', + fit: BoxFit.contain, + ), + // Positioned( + // top: 0, + // left: MediaQuery.of(context).size.width* 0.5, + // child: SizedBox( + // width: 50, + // height: 100, + // child: Image.asset( + // 'assets/app_tour/bookmark2.png', + // fit: BoxFit.contain, + // ), + // ), + // ), + ], + ), + ), + ), + ], + ), + ]; } Future _getAppVersion() async { @@ -146,6 +586,7 @@ class _BaseScaffoldState extends ConsumerState { // icon: const Icon(Icons.toggle_off_outlined), // ), MyToggle( + key: toggleKey, isOn: locale?.languageCode == 'en', knobTextWhenOn: 'ع', knobTextWhenOff: 'EN', @@ -174,6 +615,7 @@ class _BaseScaffoldState extends ConsumerState { child: Builder( builder: (BuildContext context) { return IconButton( + key:drawerKey, color: (widget.showBackButton == true) ? Colors.white : Colors.black, @@ -258,10 +700,17 @@ class _BaseScaffoldState extends ConsumerState { ), if(userId != 'guest') ListTile( +<<<<<<< HEAD leading: Icon(Icons.feedback), // title: const Text('Feedback'), title: Text(AppLocalizations.of(context)!.feedback_title), onTap: () => context.go('/feedback'), +======= + leading: Icon(Icons.manage_accounts), + // title: Text('Manage User'), + title: Text(AppLocalizations.of(context)!.manage_user,), + onTap: () => context.go('/manageuser'), +>>>>>>> aab1520305f7176b69eb4d5b8be01b832c8c0c71 ), if (role == 'admin') ListTile( @@ -339,6 +788,7 @@ class _BaseScaffoldState extends ConsumerState { label: AppLocalizations.of(context)!.country_profile, ), ], + key: bottomNavKey, selectedItemColor: Colors.black, unselectedItemColor: Colors.grey, showUnselectedLabels: true, diff --git a/pubspec.lock b/pubspec.lock index 3458fc7c..84ac165f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "88399e291da5f7e889359681a8f64b18c5123e03576b01f32a6a276611e511c3" + sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" url: "https://pub.dev" source: hosted - version: "78.0.0" + version: "76.0.0" _macros: dependency: transitive description: dart @@ -18,18 +18,18 @@ packages: dependency: transitive description: name: analyzer - sha256: "62899ef43d0b962b056ed2ebac6b47ec76ffd003d5f7c4e4dc870afe63188e33" + sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" url: "https://pub.dev" source: hosted - version: "7.1.0" + version: "6.11.0" analyzer_plugin: dependency: transitive description: name: analyzer_plugin - sha256: "1d460d14e3c2ae36dc2b32cef847c4479198cf87704f63c3c3c8150ee50c3916" + sha256: "9661b30b13a685efaee9f02e5d01ed9f2b423bd889d28a304d02d704aee69161" url: "https://pub.dev" source: hosted - version: "0.12.0" + version: "0.11.3" ansicolor: dependency: transitive description: @@ -74,50 +74,50 @@ packages: dependency: transitive description: name: build - sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0 + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.4.1" build_config: dependency: transitive description: name: build_config - sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" + sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.1" build_daemon: dependency: transitive description: name: build_daemon - sha256: "294a2edaf4814a378725bfe6358210196f5ea37af89ecd81bfa32960113d4948" + sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" url: "https://pub.dev" source: hosted - version: "4.0.3" + version: "4.0.2" build_resolvers: dependency: transitive description: name: build_resolvers - sha256: "99d3980049739a985cf9b21f30881f46db3ebc62c5b8d5e60e27440876b1ba1e" + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" url: "https://pub.dev" source: hosted - version: "2.4.3" + version: "2.4.2" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "74691599a5bc750dc96a6b4bfd48f7d9d66453eab04c7f4063134800d6a5c573" + sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" url: "https://pub.dev" source: hosted - version: "2.4.14" + version: "2.4.13" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021" + sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 url: "https://pub.dev" source: hosted - version: "8.0.0" + version: "7.3.2" built_collection: dependency: transitive description: @@ -282,42 +282,42 @@ packages: dependency: "direct dev" description: name: custom_lint - sha256: "6d509673c4dd0baa90e60dc8366bc2acc6690f16a7d44bfae31294d82c5d2a62" + sha256: "3486c470bb93313a9417f926c7dd694a2e349220992d7b9d14534dc49c15bba9" url: "https://pub.dev" source: hosted - version: "0.7.1" + version: "0.7.0" custom_lint_builder: dependency: transitive description: name: custom_lint_builder - sha256: "8cc525c7b160eb47bb1ded8b2633c0f8b907930eb986ac577aded87cdd2835fe" + sha256: "42cdc41994eeeddab0d7a722c7093ec52bd0761921eeb2cbdbf33d192a234759" url: "https://pub.dev" source: hosted - version: "0.7.1" + version: "0.7.0" custom_lint_core: dependency: transitive description: name: custom_lint_core - sha256: "6dcee8a017181941c51a110da7e267c1d104dc74bec8862eeb8c85b5c8759a9e" + sha256: "02450c3e45e2a6e8b26c4d16687596ab3c4644dd5792e3313aa9ceba5a49b7f5" url: "https://pub.dev" source: hosted - version: "0.7.1" + version: "0.7.0" custom_lint_visitor: dependency: transitive description: name: custom_lint_visitor - sha256: "14df0760dfa81b7b0c398c876045f4e4a343eb2c9d200c66163671dd3e337c1b" + sha256: bfe9b7a09c4775a587b58d10ebb871d4fe618237639b1e84d5ec62d7dfef25f9 url: "https://pub.dev" source: hosted - version: "1.0.0+7.1.0" + version: "1.0.0+6.11.0" dart_style: dependency: transitive description: name: dart_style - sha256: "27eb0ae77836989a3bc541ce55595e8ceee0992807f14511552a898ddd0d88ac" + sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "2.3.7" dbus: dependency: transitive description: @@ -433,10 +433,10 @@ packages: dependency: "direct main" description: name: fl_chart - sha256: "5276944c6ffc975ae796569a826c38a62d2abcf264e26b88fa6f482e107f4237" + sha256: "74959b99b92b9eebeed1a4049426fd67c4abc3c5a0f4d12e2877097d6a11ae08" url: "https://pub.dev" source: hosted - version: "0.70.2" + version: "0.69.2" flutter: dependency: "direct main" description: flutter @@ -597,10 +597,10 @@ packages: dependency: "direct dev" description: name: freezed - sha256: "59a584c24b3acdc5250bb856d0d3e9c0b798ed14a4af1ddb7dc1c7b41df91c9c" + sha256: "44c19278dd9d89292cf46e97dc0c1e52ce03275f40a97c5a348e802a924bf40e" url: "https://pub.dev" source: hosted - version: "2.5.8" + version: "2.5.7" freezed_annotation: dependency: "direct main" description: @@ -693,10 +693,10 @@ packages: dependency: transitive description: name: http_parser - sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" url: "https://pub.dev" source: hosted - version: "4.1.2" + version: "4.0.2" image: dependency: transitive description: @@ -781,10 +781,10 @@ packages: dependency: "direct dev" description: name: injectable_generator - sha256: b04673a4c88b3a848c0c77bf58b8309f9b9e064d9fe1df5450c8ee1675eaea1a + sha256: af403d76c7b18b4217335e0075e950cd0579fd7f8d7bd47ee7c85ada31680ba1 url: "https://pub.dev" source: hosted - version: "2.7.0" + version: "2.6.2" intl: dependency: "direct main" description: @@ -821,10 +821,10 @@ packages: dependency: "direct dev" description: name: json_serializable - sha256: b0a98230538fe5d0b60a22fb6bf1b6cb03471b53e3324ff6069c591679dd59c9 + sha256: c2fcb3920cf2b6ae6845954186420fca40bc0a8abcc84903b7801f17d7050d7c url: "https://pub.dev" source: hosted - version: "6.9.3" + version: "6.9.0" jwt_decoder: dependency: "direct main" description: @@ -861,10 +861,10 @@ packages: dependency: transitive description: name: lints - sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 + sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" url: "https://pub.dev" source: hosted - version: "5.1.1" + version: "5.0.0" logging: dependency: transitive description: @@ -1101,10 +1101,10 @@ packages: dependency: transitive description: name: pubspec_parse - sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0" url: "https://pub.dev" source: hosted - version: "1.5.0" + version: "1.4.0" recase: dependency: transitive description: @@ -1133,10 +1133,10 @@ packages: dependency: transitive description: name: riverpod_analyzer_utils - sha256: "837a6dc33f490706c7f4632c516bcd10804ee4d9ccc8046124ca56388715fdf3" + sha256: c6b8222b2b483cb87ae77ad147d6408f400c64f060df7a225b127f4afef4f8c8 url: "https://pub.dev" source: hosted - version: "0.5.9" + version: "0.5.8" riverpod_annotation: dependency: "direct main" description: @@ -1149,18 +1149,18 @@ packages: dependency: "direct dev" description: name: riverpod_generator - sha256: "120d3310f687f43e7011bb213b90a436f1bbc300f0e4b251a72c39bccb017a4f" + sha256: "63546d70952015f0981361636bf8f356d9cfd9d7f6f0815e3c07789a41233188" url: "https://pub.dev" source: hosted - version: "2.6.4" + version: "2.6.3" riverpod_lint: dependency: "direct dev" description: name: riverpod_lint - sha256: b05408412b0f75dec954e032c855bc28349eeed2d2187f94519e1ddfdf8b3693 + sha256: "83e4caa337a9840469b7b9bd8c2351ce85abad80f570d84146911b32086fbd99" url: "https://pub.dev" source: hosted - version: "2.6.4" + version: "2.6.3" rxdart: dependency: transitive description: @@ -1252,10 +1252,10 @@ packages: dependency: transitive description: name: shelf - sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 url: "https://pub.dev" source: hosted - version: "1.4.2" + version: "1.4.1" shelf_web_socket: dependency: transitive description: @@ -1280,10 +1280,10 @@ packages: dependency: transitive description: name: source_gen - sha256: "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b" + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "1.5.0" source_helper: dependency: transitive description: @@ -1444,6 +1444,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + tutorial_coach_mark: + dependency: "direct main" + description: + name: tutorial_coach_mark + sha256: df450c88d4c812bc221afd3ff948da3dc0f44c0b4fa5dbc046d6d86f2cfc9e71 + url: "https://pub.dev" + source: hosted + version: "1.2.12" typed_data: dependency: transitive description: @@ -1512,10 +1520,10 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "3ba963161bd0fe395917ba881d320b9c4f6dd3c4a233da62ab18a5025c85f1e9" + sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.3.3" url_launcher_windows: dependency: transitive description: @@ -1552,10 +1560,10 @@ packages: dependency: transitive description: name: video_player_android - sha256: "7018dbcb395e2bca0b9a898e73989e67c0c4a5db269528e1b036ca38bcca0d0b" + sha256: "391e092ba4abe2f93b3e625bd6b6a6ec7d7414279462c1c0ee42b5ab8d0a0898" url: "https://pub.dev" source: hosted - version: "2.7.17" + version: "2.7.16" video_player_avfoundation: dependency: transitive description: @@ -1685,5 +1693,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.6.0 <4.0.0" - flutter: ">=3.27.0" + dart: ">=3.5.2 <4.0.0" + flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index b382e3aa..68b42804 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -22,8 +22,8 @@ dependencies: riverpod_annotation: ^2.3.3 cupertino_icons: ^1.0.6 - fl_chart: ^0.70.2 - + fl_chart: ^0.69.2 + tutorial_coach_mark: ^1.2.12 marquee: ^2.2.3 url_launcher: ^6.3.1 # dynamic_layouts: @@ -114,6 +114,7 @@ flutter: - assets/cached_responses/sharepoint/country_leader_imgs/ - assets/edit_profile/ - assets/splash_screen/ + - assets/app_tour/ fonts: - family: Segoe