diff --git a/lib/main.dart b/lib/main.dart index 6515aea..cd91bcd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -15,6 +15,7 @@ import 'package:the_wallpaper_company/features/home/presentation/screen/wallpape import 'package:the_wallpaper_company/features/home/provider/wallpaper_provider.dart'; import 'package:the_wallpaper_company/firebase_options.dart'; +import 'package:the_wallpaper_company/onboardingScreen/introPage.dart'; final GlobalKey navigatorKey = GlobalKey(); @@ -108,7 +109,7 @@ class _MyAppState extends State { GlobalCupertinoLocalizations.delegate, ], supportedLocales: LanguageProvider.supportedLocales, - home: const HomeScreen(), + home: const IntroPage1(), ); }, ); diff --git a/lib/onboardingScreen/introPage.dart b/lib/onboardingScreen/introPage.dart new file mode 100644 index 0000000..13510bd --- /dev/null +++ b/lib/onboardingScreen/introPage.dart @@ -0,0 +1,382 @@ +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:the_wallpaper_company/features/home/presentation/screen/home_screen.dart'; +import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; + +class IntroPage1 extends StatefulWidget { + const IntroPage1({super.key}); + + @override + State createState() => _IntroPage1State(); +} + +class _IntroPage1State extends State { + final GlobalKey searchKey = GlobalKey(); + final GlobalKey langKey = GlobalKey(); + final GlobalKey themeKey = GlobalKey(); + final GlobalKey categoryKey = GlobalKey(); + final GlobalKey favKey = GlobalKey(); + + List targets = []; + TutorialCoachMark? tutorial; + + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) => checkTutorial()); + } + + // Check if tutorial was already shown + Future checkTutorial() async { + final prefs = await SharedPreferences.getInstance(); + bool isTutorialShown = prefs.getBool('tutorial_shown') ?? false; + + if (!isTutorialShown) { + showTutorial(); + // Save that tutorial has been shown + await prefs.setBool('tutorial_shown', true); + } else { + // Navigate directly to home + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (_) => const HomeScreen()), + ); + } + } + + void showTutorial() { + Widget buildText(String text) { + return Container( + padding: const EdgeInsets.all(14), + decoration: BoxDecoration( + color: Colors.deepPurple, + borderRadius: BorderRadius.circular(14), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.3), + blurRadius: 8, + offset: const Offset(0, 4), + ), + ], + ), + child: Text( + text, + textAlign: TextAlign.center, + style: const TextStyle( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.w600, + ), + ), + ); + } + + targets = [ + TargetFocus( + identify: "Search", + keyTarget: searchKey, + contents: [ + TargetContent( + align: ContentAlign.bottom, + child: buildText("Search wallpapers easily here 🔍"), + ), + ], + ), + TargetFocus( + identify: "Language", + keyTarget: langKey, + contents: [ + TargetContent( + align: ContentAlign.bottom, + child: buildText("Switch between different languages 🌍"), + ), + ], + ), + TargetFocus( + identify: "Theme", + keyTarget: themeKey, + contents: [ + TargetContent( + align: ContentAlign.bottom, + child: buildText("Toggle between Light and Dark mode 🌗"), + ), + ], + ), + TargetFocus( + identify: "Category", + keyTarget: categoryKey, + contents: [ + TargetContent( + align: ContentAlign.bottom, + child: buildText("Browse wallpapers by category 🎨"), + ), + ], + ), + TargetFocus( + identify: "Favorites", + keyTarget: favKey, + contents: [ + TargetContent( + align: ContentAlign.top, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + buildText("Access your favorite wallpapers here ❤️"), + const SizedBox(height: 20), + ElevatedButton( + onPressed: () { + tutorial?.finish(); + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (_) => const HomeScreen()), + ); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: Colors.deepPurple, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + padding: const EdgeInsets.symmetric( + horizontal: 24, vertical: 10), + ), + child: const Text( + "Done", + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + ], + ), + ), + ], + ), + ]; + + tutorial = TutorialCoachMark( + targets: targets, + colorShadow: Colors.black.withOpacity(0.7), + paddingFocus: 8, + opacityShadow: 0.8, + skipWidget: Positioned( + top: 50, + left: 20, + child: GestureDetector( + onTap: () { + tutorial?.finish(); + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (_) => const HomeScreen()), + ); + }, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8), + decoration: BoxDecoration( + color: Colors.white70, + borderRadius: BorderRadius.circular(8), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.2), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ), + child: const Text( + "SKIP", + style: TextStyle( + color: Colors.black87, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + ), + ), + onFinish: () { + Navigator.pushReplacement( + context, + MaterialPageRoute(builder: (_) => const HomeScreen()), + ); + }, + onClickTarget: (target) {}, + ); + + tutorial?.show(context: context); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.grey[100], + appBar: AppBar( + backgroundColor: Colors.grey[100], + elevation: 0, + title: Row( + children: [ + Expanded( + child: Container( + key: searchKey, + height: 40, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(20), + ), + child: const Row( + children: [ + SizedBox(width: 10), + Icon(Icons.search, color: Colors.black54), + SizedBox(width: 8), + Text( + 'Search wallpapers...', + style: TextStyle(color: Colors.black54), + ), + ], + ), + ), + ), + const SizedBox(width: 10), + Container( + key: langKey, + width: 40, + height: 40, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(20), + ), + child: const Center( + child: Text( + 'EN', + style: TextStyle(color: Colors.black87), + ), + ), + ), + const SizedBox(width: 10), + Container( + key: themeKey, + width: 40, + height: 40, + margin: const EdgeInsets.only(right: 16), + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(20), + ), + child: const Icon(Icons.wb_sunny, color: Colors.black54), + ), + ], + ), + ), + body: SafeArea( + child: Stack( + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 60), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: SizedBox( + key: categoryKey, + height: 80, + child: ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: 5, + separatorBuilder: (_, __) => + const SizedBox(width: 12), + itemBuilder: (context, index) => Container( + width: 100, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(20), + ), + ), + ), + ), + ), + const SizedBox(height: 10), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: GridView.builder( + physics: const BouncingScrollPhysics(), + gridDelegate: + const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + mainAxisSpacing: 10, + crossAxisSpacing: 10, + childAspectRatio: 0.75, + ), + itemCount: 12, + itemBuilder: (context, index) => Container( + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(20), + ), + ), + ), + ), + ), + ], + ), + ), + Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.only(bottom: 20.0), + child: Container( + key: favKey, + width: 220, + height: 70, + decoration: BoxDecoration( + color: Colors.grey[200], + borderRadius: BorderRadius.circular(40), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.3), + blurRadius: 8, + offset: const Offset(0, 4), + ), + ], + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + const Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.home, color: Colors.black54), + SizedBox(height: 4), + Text('Home', + style: TextStyle( + color: Colors.black54, fontSize: 12)), + ], + ), + Container( + width: 1, + height: 36, + color: Colors.grey[400], + ), + const Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.favorite_border, color: Colors.black54), + SizedBox(height: 4), + Text('Favorites', + style: TextStyle( + color: Colors.black54, fontSize: 12)), + ], + ), + ], + ), + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 8931f95..0b6c993 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -778,6 +778,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.3" + tutorial_coach_mark: + dependency: "direct main" + description: + name: tutorial_coach_mark + sha256: "5a325d53bcf16ce7a969e2ab8d4dc9610f39ee3eab2b3cc57d5c98936129b891" + url: "https://pub.dev" + source: hosted + version: "1.3.3" typed_data: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 894a8fe..e242806 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -59,6 +59,8 @@ dependencies: firebase_analytics: ^12.0.1 firebase_messaging: ^16.0.1 flutter_local_notifications: ^19.4.1 + tutorial_coach_mark: ^1.3.3 + dev_dependencies: flutter_test: