import 'dart:async'; import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; import 'package:uae_stat/config/theme/theme_provider.dart'; import 'package:uae_stat/domain/use_cases/language.dart'; import 'package:uae_stat/l10n/app_localizations.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/config/api_config.dart'; import 'package:uae_stat/lib/core/routing/app_router.dart'; import 'package:uae_stat/presentation/routes/drawer_routes/app_drawer.dart'; class BaseScaffold extends ConsumerStatefulWidget { const BaseScaffold({ super.key, required this.body, required this.title, this.actions, this.showDivider = false, this.dividerColor, this.navBackArrow, this.showBackButton = false, this.colorChange = false, this.mycenterTitle = false, this.appbarColor = Colors.white, this.mytitleColor, this.bottomColor, this.backgroundColor = Colors.white, }); final Widget body; final Widget title; final Widget? navBackArrow; final Color? dividerColor; final bool showDivider; final bool showBackButton; final bool colorChange; final bool? mycenterTitle; final List? actions; final Color? bottomColor; final Color? appbarColor, mytitleColor; final Color? backgroundColor; @override _BaseScaffoldState createState() => _BaseScaffoldState(); } class _BaseScaffoldState extends ConsumerState { // final _pb = PocketBase('https://pb.venbait.in'); late TutorialCoachMark tutorialCoachMark; late List appBarTargets; final GlobalKey bottomNavKey = GlobalKey(); final GlobalKey toggleKey = GlobalKey(); final GlobalKey drawerKey = GlobalKey(); late double toggleHeight = 0; late final Locale locale; List> notifications = []; List userReadedNotiOrNot = []; int notificationCount = 0; @override void initState() { super.initState(); locale = ref.read(localeProvider) ?? const Locale('en'); WidgetsBinding.instance.addPostFrameCallback((_) { _startAppbarTour(); _loadReadNotifications(); fetchNotifications(locale.languageCode); }); } //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; }, )..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; } Future handleSkip() async { tutorialCoachMark.skip(); 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; } void _initTarget() { final double screenWidth = MediaQuery.of(context).size.width; final double screenHeight = MediaQuery.of(context).size.height; appBarTargets = [ TargetFocus( enableTargetTab: false, 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: Column( children: [ Align( alignment: Alignment.bottomRight, child: Padding( padding: const EdgeInsets.only(right: 10.0), child: Text( '5/7', style: TextStyle( color: Colors.white, fontSize: 14, fontFamily: context.translate( 'Roboto', 'NotoKufi', ), ), ), ), ), 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( icon: const Icon( Icons.arrow_back, // color: Colors.white, color: Colors.grey, ), onPressed: () { if (locale.languageCode == 'ar') { tutorialCoachMark.next(); } else { tutorialCoachMark.finish(); ref .read(scaffoldTourProvider.notifier) .state = true; ref .read(previousChartsTourProvider .notifier) .state = false; context.go( AppRoutes.datasetDetailPath( dataSet: 'marriages', bgColor: '0xFFAA8E83', mainTopic: 'Demography', title: 'Marriages', kpi: 'marriages', ), ); } }, ), ), 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( icon: const Icon(Icons.arrow_forward, color: Colors.white), onPressed: () { if (locale.languageCode == 'ar') { tutorialCoachMark.finish(); ref .read(scaffoldTourProvider.notifier) .state = true; ref .read(previousChartsTourProvider .notifier) .state = false; context.go( AppRoutes.datasetDetailPath( dataSet: 'marriages', bgColor: '0xFFAA8E83', mainTopic: 'اجتماعي', title: 'الزواج', key: 'home', kpi: 'marriages', ), ); } else { tutorialCoachMark.next(); } }, ), ), ], ), ], ), ], ), ), ], ), ), ), ], ), TargetFocus( enableTargetTab: false, 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, space: 55, gap: 55, ), TargetContent( align: ContentAlign.bottom, child: SizedBox( width: double.infinity, height: MediaQuery.of(context).size.height * 0.80, child: Stack( children: [ Positioned( bottom: 40, left: 16, right: 16, child: Column( children: [ Align( alignment: Alignment.bottomRight, child: Padding( padding: const EdgeInsets.only(right: 10.0), child: Text( '6/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( // 'Skip', 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( icon: const Icon( Icons.arrow_back, // color: Colors.white, color: Colors.grey, ), onPressed: () { locale.languageCode == 'ar' ? tutorialCoachMark.next() : 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( icon: const Icon( Icons.arrow_forward, color: Colors.white, ), onPressed: () { locale.languageCode == 'ar' ? tutorialCoachMark.previous() : tutorialCoachMark.next(); }, ), ), ], ), ], ), ], ), ), ], ), ), ), TargetContent( padding: EdgeInsets.only( right: locale.languageCode == 'ar' ? 0 : screenWidth * 0.7, top: 25, left: locale.languageCode == 'ar' ? screenWidth * 0.7 : 0, ), align: locale.languageCode == 'ar' ? ContentAlign.left : ContentAlign.right, child: Container( width: 200, height: 100, child: Stack( children: [ Image.asset( locale.languageCode == 'ar' ? 'assets/app_tour/rightDown.png' // Arabic locale image : 'assets/app_tour/leftDown2.png', // Default image 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( enableTargetTab: false, identify: 'toggleKey', keyTarget: toggleKey, shape: ShapeLightFocus.RRect, radius: 0, paddingFocus: 0, // Rounded rectangle highlight contents: [ createTargetContent( text: AppLocalizations.of(context)!.toggle, space: 50, 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: 37, left: 16, right: 16, child: Column( children: [ Align( alignment: Alignment.bottomRight, child: Padding( padding: const EdgeInsets.only(right: 10.0), child: Text( '7/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, border: Border.all( color: Colors.white, width: 2.0), ), child: IconButton( icon: Icon( locale.languageCode == 'ar' ? Icons.arrow_forward : Icons.arrow_back, // color: Colors.white, color: Colors.grey, ), onPressed: () { tutorialCoachMark.previous(); }, ), ), const SizedBox(width: 10), ElevatedButton( onPressed: () async { 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; tutorialCoachMark.finish(); }, style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), side: const BorderSide(color: Colors.white), backgroundColor: Colors.white, elevation: 0, ), child: Text( AppLocalizations.of(context)!.got_it, style: TextStyle( fontFamily: context.translate( 'Roboto', 'NotoKufi', ), color: Color(0xFF7DAFBC), fontSize: 14, ), ), ), ], ), ], ), ], ), ), ], ), ), ), TargetContent( padding: EdgeInsets.only( left: locale.languageCode == 'ar' ? 0 : screenWidth * 0.7, top: toggleHeight, right: locale.languageCode == 'ar' ? screenWidth * 0.7 : 0, ), align: locale.languageCode == 'ar' ? ContentAlign.right : ContentAlign.left, child: Container( width: 200, height: 200, child: Stack( children: [ Image.asset( locale.languageCode == 'ar' ? 'assets/app_tour/leftDown2.png' // Arabic locale image : 'assets/app_tour/rightDown.png', // Default image fit: BoxFit.contain, ) ], ), ), ), ], ), ]; } Future _loadReadNotifications() async { final prefs = await SharedPreferences.getInstance(); userReadedNotiOrNot = prefs.getStringList('read_notification_ids') ?? []; } Future fetchNotifications(locale) async { final baseUrl = apiUrl + 'api/getNotification'; try { final response = await http.get(Uri.parse('$baseUrl?language=$locale'), headers: {'APP_SIGNATURE': 'fcsc.gov.ae.X7pL9qZm2A'}); if (response.statusCode == 200) { final Map jsonResponse = jsonDecode(response.body); // Decode JSON if (jsonResponse['message'] == 'Success') { setState(() { notifications = List>.from( jsonResponse['data']); // Assign decoded data // isLoading = false; }); _processNotifications(notifications, userReadedNotiOrNot); } else { throw Exception('Failed to load data'); } } else { throw Exception( 'Failed to load data with status code ${response.statusCode}'); } } catch (e) {} } void _processNotifications( List> notification, List push) { int count = 0; for (var product in notification) { if (push.contains(product['id'])) { count++; } } notificationCount = count; } // Future logout() async { // final prefs = await SharedPreferences.getInstance(); // // setState(() { // // isLoggedOut = true; // // }); // // prefs.clear(); // await _repo.logout(); // // state = const AsyncData(null); // // _pb.authStore.clear(); // // await _secureStorage.delete(key: "FlutterSecureStorage.session"); // prefs.clear(); // context.go('/login'); // } // void _showThemeDialog(BuildContext context) async { // AppTheme? result = await showDialog( // context: context, // builder: (context) => ThemeSelectorDialog(initialTheme: AppTheme.system), // ); // // if (result != null) { // // You can now use `result` to apply the selected theme // print('Selected theme: $result'); // final prefs = await SharedPreferences.getInstance(); // final userId = prefs.getString('userId') ?? ''; // // Example: save to PocketBase or local preferences // final themeService = ThemeBaseService(); // await themeService.updateUserTheme(userId, result.name); // } // } // void showThemeDialog(BuildContext context, WidgetRef ref) async { // final currentTheme = ref.read(themeProvider); // final current = currentTheme == ThemeMode.light // ? AppTheme.light // : currentTheme == ThemeMode.dark // ? AppTheme.dark // : AppTheme.system; // // final selected = await showDialog( // context: context, // builder: (context) => ThemeSelectorDialog(initialTheme: current), // ); // // if (selected != null) { // ref.read(themeProvider.notifier).updateTheme(selected); // final themeService = ThemeBaseService(); // await themeService.updateUserTheme(userId, selected.name); // } // } // void showThemeDialog(BuildContext context, WidgetRef ref) async { // final currentTheme = ref.read(themeProvider); // final current = currentTheme == ThemeMode.light // ? AppTheme.light // : currentTheme == ThemeMode.dark // ? AppTheme.dark // : AppTheme.system; // // final selected = await showDialog( // context: context, // builder: (context) => ThemeSelectorDialog(initialTheme: current), // ); // // if (selected != null) { // // Update app theme locally // ref.read(themeProvider.notifier).updateTheme(selected); // // // Detect real system brightness if 'system' is selected // String themeToSend; // if (selected == AppTheme.system) { // final brightness = MediaQuery.of(context).platformBrightness; // themeToSend = brightness == Brightness.dark ? 'dark' : 'light'; // } else { // themeToSend = selected.name; // } // // // Save to PocketBase // await ThemeBaseService().updateUserTheme(userId, themeToSend); // } // } @override Widget build(BuildContext context) { final locale = ref.watch(localeProvider); double mywidth = MediaQuery.of(context).size.width; final isDarkTheme = ref.watch(themeProvider) == ThemeMode.dark; return Scaffold( backgroundColor: widget.backgroundColor, // backgroundColor: Colors.white, appBar: AppBar( title: Padding( padding: EdgeInsets.only(top: 10), child: Align( alignment: (locale?.languageCode == 'ar') ? Alignment.centerRight : Alignment.centerLeft, child: DefaultTextStyle( style: TextStyle( color: isDarkTheme ? Colors.white : Colors.black, // color: widget.colorChange ? Colors.white : Color(0xFFFFFFFF), fontSize: 22, fontFamily: context.translate( 'Roboto', 'NotoKufi', ), fontWeight: FontWeight.w500, ), child: widget.title, ), ), ), scrolledUnderElevation: 0, titleSpacing: 0, flexibleSpace: Container( decoration: BoxDecoration( color: isDarkTheme ? Color(0xFF000000) : Color(0xFFFFFFFF), ), ), // flexibleSpace: (isDarkTheme && currentRoute == '/myhomepage') // ? Container( // decoration: const BoxDecoration( // image: DecorationImage( // image: AssetImage('assets/dark_bg.png'), // fit: BoxFit.cover, // ), // ), // ) // : (isDarkTheme && currentRoute == '/uaenumbers') // ? Container( // decoration: const BoxDecoration( // color: Color(0xFF333333), // ), // ) // : null, backgroundColor: widget.appbarColor ?? Colors.white, leadingWidth: widget.showBackButton ? mywidth * 0.18 : null, bottom: widget.showDivider ? PreferredSize( preferredSize: Size.fromHeight(1), // Height of the line child: Container( color: widget.dividerColor, // Line color height: 1, // Line thickness ), ) : null, // bottom: widget.showDivider // ? PreferredSize( // preferredSize: Size.fromHeight(1), // Height of the line // child: Container( // color: widget.dividerColor, // width: double.infinity,// Line color // height: 1, // Line thickness // ), // ) // : null, actions: widget.actions ?? [ // IconButton( // onPressed: () {}, // icon: const Icon(Icons.toggle_off_outlined), // ), MyToggle( key: toggleKey, isOn: locale?.languageCode == 'en', knobTextWhenOn: 'ع', knobTextWhenOff: 'EN', pathColorWhenOn: Color(0xFFD9D9D9), pathColorWhenOff: Color(0xFFD9D9D9), knobTextStyleWhenOn: TextStyle( color: Color(0xFF010101), fontWeight: FontWeight.bold, ), knobTextStyleWhenOff: TextStyle( color: Color(0xFF010101), fontWeight: FontWeight.bold, ), onTap: () { ref.read(localeProvider.notifier).toggleLocale(); }, ), ], leading: Padding( padding: const EdgeInsets.only(top: 7.0, left: 4), child: Row( mainAxisSize: MainAxisSize.min, children: [ if (widget.showBackButton == true) SizedBox( width: 25, height: 25, child: IconButton( padding: EdgeInsets.zero, constraints: BoxConstraints(), // color: widget.colorChange ? Colors.white : Colors.black, // color: isDarkTheme // ? widget.colorChange // ? Colors.black // : Colors.white // : widget.colorChange // ? Colors.white // : Colors.black, color: isDarkTheme ? Colors.white : Colors.black, icon: const Icon(Icons.arrow_back_ios_new, size: 24), onPressed: () { if (widget.navBackArrow is Text && (widget.navBackArrow as Text).data == 'notification') { context.go('/notification'); } else { context.pop(); } }, ), ), SizedBox( width: 7, ), Builder( builder: (BuildContext context) { return SizedBox( width: 30, height: 30, child: IconButton( padding: EdgeInsets.zero, constraints: BoxConstraints(), key: drawerKey, color: isDarkTheme ? Colors.white : Color(0xFF000000), icon: const Icon(Icons.menu, size: 30), onPressed: () { Scaffold.of(context).openDrawer(); }, ), ); }, ), ], ), ), ), drawer: const UaeStatsDrawer(), bottomNavigationBar: SizedBox(key: bottomNavKey, height: 0), // BottomNavigationBar( // backgroundColor: isDarkTheme ? Color(0xFF00000080) : Colors.white, // currentIndex: _getSelectedIndex(currentRoute), // onTap: (index) => _onItemTapped(context, index), // type: BottomNavigationBarType.fixed, // items: [ // BottomNavigationBarItem( // icon: Padding( // padding: // const EdgeInsets.only(bottom: 4), // Adjust this for spacing // child: Image.asset( // BottomBarAssetIconPath.home, // color: _getSelectedIndex(currentRoute) == 0 // ? Colors.black // : Color(0xFF989898), // width: 23.98, // height: 25, // ), // ), // // label: 'Home', // label: AppLocalizations.of(context)!.nav_home, // ), // BottomNavigationBarItem( // // icon: Icon(Icons.map), // icon: Padding( // padding: // const EdgeInsets.only(bottom: 4), // Adjust this for spacing // child: Image.asset( // BottomBarAssetIconPath.uaeMap, // color: _getSelectedIndex(currentRoute) == 1 // ? Colors.black // : Color(0xFF989898), // width: 23.98, // height: 25, // ), // ), // // label: 'UAE Numbers' // label: AppLocalizations.of(context)!.nav_uae, // ), // BottomNavigationBarItem( // icon: Padding( // padding: // const EdgeInsets.only(bottom: 4), // Adjust this for spacing // child: Image.asset( // BottomBarAssetIconPath.ranking, // color: _getSelectedIndex(currentRoute) == 2 // ? Colors.black // : Color(0xFF989898), // width: 23.98, // height: 25, // ), // ), // // label: 'Competitiveness', // label: AppLocalizations.of(context)!.nav_competitiveness, // ), // BottomNavigationBarItem( // icon: Padding( // padding: // const EdgeInsets.only(bottom: 4), // Adjust this for spacing // child: Image.asset( // BottomBarAssetIconPath.globe, // color: _getSelectedIndex(currentRoute) == 3 // ? Colors.black // : Color(0xFF989898), // width: 23.98, // height: 25, // ), // ), // // label: 'Country Profile', // label: AppLocalizations.of(context)!.country_profile, // ), // ], // key: bottomNavKey, // selectedItemColor: Colors.black, // unselectedItemColor: Colors.grey, // selectedLabelStyle: TextStyle( // fontFamily: context.translate( // 'Roboto', // 'NotoKufi', // ), // fontSize: 10, // Font size for unselected label // ), // unselectedLabelStyle: TextStyle( // fontFamily: context.translate( // 'Roboto', // 'NotoKufi', // ), // fontSize: 10, // Font size for unselected label // ), // showUnselectedLabels: true, // ), body: widget.body, ); } }