diff --git a/lib/app/modules/home/views/home_page_body.dart b/lib/app/modules/home/views/home_page_body.dart index a409e8ee..508c831d 100644 --- a/lib/app/modules/home/views/home_page_body.dart +++ b/lib/app/modules/home/views/home_page_body.dart @@ -4,6 +4,8 @@ import 'package:get/get.dart'; import 'package:taskwarrior/app/modules/home/views/show_tasks.dart'; import 'package:taskwarrior/app/modules/home/views/show_tasks_replica.dart'; import 'package:taskwarrior/app/modules/home/views/tasks_builder.dart'; +import 'package:taskwarrior/app/modules/home/views/tutorial_modal.dart'; +import 'package:taskwarrior/app/utils/app_settings/app_settings.dart'; import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; import 'package:taskwarrior/app/utils/themes/theme_extension.dart'; import 'package:taskwarrior/app/utils/language/sentence_manager.dart'; @@ -13,10 +15,44 @@ class HomePageBody extends StatelessWidget { final HomeController controller; const HomePageBody({required this.controller, super.key}); + void _showTutorialModal(BuildContext context) { + Future.delayed( + const Duration(milliseconds: 500), + () async { + bool promptShown = await SaveTourStatus.getTutorialPromptShown(); + if (!promptShown && context.mounted) { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext dialogContext) { + return TutorialModal( + onYes: () async { + await SaveTourStatus.saveTutorialPromptShown(true); + if (dialogContext.mounted) { + Navigator.of(dialogContext).pop(); + controller.initInAppTour(); + controller.tutorialCoachMark.show(context: context); + } + }, + onNo: () async { + await SaveTourStatus.saveTutorialPromptShown(true); + await SaveTourStatus.disableAllTutorials(); + if (dialogContext.mounted) { + Navigator.of(dialogContext).pop(); + } + }, + ); + }, + ); + } + }, + ); + } + @override Widget build(BuildContext context) { controller.initInAppTour(); - controller.showInAppTour(context); + _showTutorialModal(context); TaskwarriorColorTheme tColors = Theme.of(context).extension()!; return DoubleBackToCloseApp( diff --git a/lib/app/modules/home/views/tutorial_modal.dart b/lib/app/modules/home/views/tutorial_modal.dart new file mode 100644 index 00000000..be748142 --- /dev/null +++ b/lib/app/modules/home/views/tutorial_modal.dart @@ -0,0 +1,134 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:taskwarrior/app/utils/app_settings/app_settings.dart'; +import 'package:taskwarrior/app/utils/language/sentence_manager.dart'; +import 'package:taskwarrior/app/utils/themes/theme_extension.dart'; + +class TutorialModal extends StatelessWidget { + final VoidCallback onYes; + final VoidCallback onNo; + + const TutorialModal({ + super.key, + required this.onYes, + required this.onNo, + }); + + @override + Widget build(BuildContext context) { + TaskwarriorColorTheme tColors = + Theme.of(context).extension()!; + final sentences = + SentenceManager(currentLanguage: AppSettings.selectedLanguage) + .sentences; + + return Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + elevation: 10, + backgroundColor: tColors.dialogBackgroundColor, + child: Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Icon + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: tColors.primaryBackgroundColor?.withValues(alpha: 0.3), + shape: BoxShape.circle, + ), + child: Icon( + Icons.school_outlined, + size: 48, + color: tColors.primaryTextColor, + ), + ), + const SizedBox(height: 20), + + // Title + Text( + sentences.tutorialModalWelcome, + style: GoogleFonts.poppins( + fontSize: 24, + fontWeight: FontWeight.bold, + color: tColors.primaryTextColor, + ), + ), + const SizedBox(height: 12), + + // Message + Text( + sentences.tutorialModalMessage, + textAlign: TextAlign.center, + style: GoogleFonts.poppins( + fontSize: 16, + color: tColors.primaryTextColor?.withValues(alpha: 0.8), + height: 1.5, + ), + ), + const SizedBox(height: 28), + + // Buttons - Vertical Layout + Column( + mainAxisSize: MainAxisSize.min, + children: [ + // Primary Action: Keep Tutorials (with outline and filled background) + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: onYes, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 16), + backgroundColor: tColors.primaryBackgroundColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + side: BorderSide( + color: tColors.primaryBackgroundColor ?? Colors.blue, + width: 2, + ), + ), + elevation: 2, + ), + child: Text( + sentences.tutorialModalKeepTutorials, + style: GoogleFonts.poppins( + fontSize: 16, + fontWeight: FontWeight.w600, + color: tColors.primaryTextColor, + ), + ), + ), + ), + const SizedBox(height: 12), + // Secondary Action: Skip all Tutorials (text button, no outline, smaller font) + SizedBox( + width: double.infinity, + child: TextButton( + onPressed: onNo, + style: TextButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: Text( + sentences.tutorialModalSkipAllTutorials, + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w500, + color: tColors.primaryTextColor?.withValues(alpha: 0.7), + ), + ), + ), + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/lib/app/utils/app_settings/save_tour_status.dart b/lib/app/utils/app_settings/save_tour_status.dart index 11b23689..1d669f34 100644 --- a/lib/app/utils/app_settings/save_tour_status.dart +++ b/lib/app/utils/app_settings/save_tour_status.dart @@ -62,4 +62,22 @@ class SaveTourStatus { static Future getTaskSwipeTutorialStatus() async { return _preferences?.getBool('task_swipe_tutorial_completed') ?? false; } + + static Future saveTutorialPromptShown(bool status) async { + await _preferences?.setBool('tutorial_prompt_shown', status); + } + + static Future getTutorialPromptShown() async { + return _preferences?.getBool('tutorial_prompt_shown') ?? false; + } + + static Future disableAllTutorials() async { + await saveReportsTourStatus(true); + await saveInAppTourStatus(true); + await saveFilterTourStatus(true); + await saveProfileTourStatus(true); + await saveDetailsTourStatus(true); + await saveManageTaskServerTourStatus(true); + await saveTaskSwipeTutorialStatus(true); + } } diff --git a/lib/app/utils/language/bengali_sentences.dart b/lib/app/utils/language/bengali_sentences.dart index 4768b418..88388980 100644 --- a/lib/app/utils/language/bengali_sentences.dart +++ b/lib/app/utils/language/bengali_sentences.dart @@ -664,6 +664,16 @@ class BengaliSentences extends Sentences { String get logs => 'লগস'; @override String get checkAllDebugLogsHere => 'এখানে সমস্ত ডিবাগ লগ পরীক্ষা করুন'; + + @override + String get tutorialModalWelcome => 'স্বাগতম!'; + @override + String get tutorialModalMessage => + 'আপনি কি এই অ্যাপটি কীভাবে ব্যবহার করতে হয় তা শেখার জন্য একটি দ্রুত টিউটোরিয়াল দেখতে চান?'; + @override + String get tutorialModalKeepTutorials => 'টিউটোরিয়াল রাখুন'; + @override + String get tutorialModalSkipAllTutorials => 'সমস্ত টিউটোরিয়াল এড়িয়ে যান'; // সেটিংস @override String get syncSetting => 'সিঙ্ক সেটিংস'; diff --git a/lib/app/utils/language/english_sentences.dart b/lib/app/utils/language/english_sentences.dart index 6e631539..c5c45ee1 100644 --- a/lib/app/utils/language/english_sentences.dart +++ b/lib/app/utils/language/english_sentences.dart @@ -653,6 +653,16 @@ class EnglishSentences extends Sentences { String get logs => 'Logs'; @override String get checkAllDebugLogsHere => 'Check all debug logs here'; + + @override + String get tutorialModalWelcome => 'Welcome!'; + @override + String get tutorialModalMessage => + 'Would you like to see a quick tutorial to learn how to use this app?'; + @override + String get tutorialModalKeepTutorials => 'Keep Tutorials'; + @override + String get tutorialModalSkipAllTutorials => 'Skip all Tutorials'; // Settings @override String get syncSetting => 'Sync Settings'; diff --git a/lib/app/utils/language/french_sentences.dart b/lib/app/utils/language/french_sentences.dart index 6558fc35..eb239b56 100644 --- a/lib/app/utils/language/french_sentences.dart +++ b/lib/app/utils/language/french_sentences.dart @@ -682,6 +682,15 @@ class FrenchSentences extends Sentences { String get checkAllDebugLogsHere => 'Vérifiez tous les journaux de débogage ici'; + @override + String get tutorialModalWelcome => 'Bienvenue!'; + @override + String get tutorialModalMessage => + 'Souhaitez-vous voir un tutoriel rapide pour apprendre à utiliser cette application?'; + @override + String get tutorialModalKeepTutorials => 'Conserver les tutoriels'; + @override + String get tutorialModalSkipAllTutorials => 'Ignorer tous les tutoriels'; // Paramètres @override String get syncSetting => 'Paramètres de Synchronisation'; diff --git a/lib/app/utils/language/hindi_sentences.dart b/lib/app/utils/language/hindi_sentences.dart index fd148096..bc627afb 100644 --- a/lib/app/utils/language/hindi_sentences.dart +++ b/lib/app/utils/language/hindi_sentences.dart @@ -642,6 +642,16 @@ class HindiSentences extends Sentences { String get logs => 'लॉग्स'; @override String get checkAllDebugLogsHere => 'यहाँ सभी डिबग लॉग्स देखें'; + + @override + String get tutorialModalWelcome => 'स्वागत है!'; + @override + String get tutorialModalMessage => + 'क्या आप इस ऐप का उपयोग करना सीखने के लिए एक त्वरित ट्यूटोरियल देखना चाहेंगे?'; + @override + String get tutorialModalKeepTutorials => 'ट्यूटोरियल रखें'; + @override + String get tutorialModalSkipAllTutorials => 'सभी ट्यूटोरियल छोड़ें'; // सेटिंग @override String get syncSetting => 'सिंक सेटिंग'; diff --git a/lib/app/utils/language/marathi_sentences.dart b/lib/app/utils/language/marathi_sentences.dart index c4abf2d9..ca9703d9 100644 --- a/lib/app/utils/language/marathi_sentences.dart +++ b/lib/app/utils/language/marathi_sentences.dart @@ -665,6 +665,15 @@ class MarathiSentences extends Sentences { @override String get checkAllDebugLogsHere => 'येथे सर्व डीबग लॉग्ज तपासा'; + @override + String get tutorialModalWelcome => 'स्वागत आहे!'; + @override + String get tutorialModalMessage => + 'तुम्हाला हे अॅप वापरण्याचे शिकण्यासाठी एक जलद ट्यूटोरियल पहायचा आहे का?'; + @override + String get tutorialModalKeepTutorials => 'ट्यूटोरियल ठेवा'; + @override + String get tutorialModalSkipAllTutorials => 'सर्व ट्यूटोरियल सोडा'; // शेटिंग @override String get syncSetting => 'सिंक शेटिंग'; diff --git a/lib/app/utils/language/sentences.dart b/lib/app/utils/language/sentences.dart index 77cb1877..f6643471 100644 --- a/lib/app/utils/language/sentences.dart +++ b/lib/app/utils/language/sentences.dart @@ -350,4 +350,10 @@ abstract class Sentences { String get profilePageChangeProfileMode; String get profilePageSelectProfileMode; String get profilePageSuccessfullyChangedProfileModeTo; + + // Tutorial modal strings + String get tutorialModalWelcome; + String get tutorialModalMessage; + String get tutorialModalKeepTutorials; + String get tutorialModalSkipAllTutorials; } diff --git a/lib/app/utils/language/spanish_sentences.dart b/lib/app/utils/language/spanish_sentences.dart index 17d73340..7003b838 100644 --- a/lib/app/utils/language/spanish_sentences.dart +++ b/lib/app/utils/language/spanish_sentences.dart @@ -670,6 +670,15 @@ class SpanishSentences extends Sentences { String get checkAllDebugLogsHere => 'Consulta todos los registros de depuración aquí'; + @override + String get tutorialModalWelcome => '¡Bienvenido!'; + @override + String get tutorialModalMessage => + '¿Te gustaría ver un tutorial rápido para aprender a usar esta aplicación?'; + @override + String get tutorialModalKeepTutorials => 'Mantener tutoriales'; + @override + String get tutorialModalSkipAllTutorials => 'Omitir todos los tutoriales'; // @override String get syncSetting => 'Configuración de sincronización';