diff --git a/app/lib/screens/wizard/page1.dart b/app/lib/screens/wizard/page1.dart index 8da9a1da9..9028c5790 100644 --- a/app/lib/screens/wizard/page1.dart +++ b/app/lib/screens/wizard/page1.dart @@ -1,19 +1,104 @@ import 'package:flutter/material.dart'; -import 'package:threebotlogin/widgets/wizard/common_page.dart'; +import 'package:flutter_svg/svg.dart'; -class Page1 extends StatelessWidget { +class Page1 extends StatefulWidget { const Page1({super.key}); + @override + State createState() => _Page1State(); +} + +class _Page1State extends State with SingleTickerProviderStateMixin { + late AnimationController _animationController; + late Animation _fadeAnimation; + late Animation _slideAnimation; + + @override + void initState() { + super.initState(); + _animationController = AnimationController( + duration: const Duration(milliseconds: 800), + vsync: this, + ); + + _fadeAnimation = Tween( + begin: 0.0, + end: 1.0, + ).animate(CurvedAnimation( + parent: _animationController, + curve: Curves.easeOut, + )); + + _slideAnimation = Tween( + begin: const Offset(0, 0.3), + end: Offset.zero, + ).animate(CurvedAnimation( + parent: _animationController, + curve: Curves.easeOut, + )); + + _animationController.forward(); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { - return const CommonPage( - title: 'WELCOME TO', - subtitle: '', - imagePath: 'assets/TF_logo.svg', - widthPercentage: 0.65, - heightPercentage: 0.25, - description: - 'ThreeFold Connect is your main access point to the ThreeFold Grid, ThreeFold Token, and more. Please allow us to quickly show you around!', + final theme = Theme.of(context); + final colorScheme = theme.colorScheme; + + return FadeTransition( + opacity: _fadeAnimation, + child: SlideTransition( + position: _slideAnimation, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Spacer(flex: 1), + // Logo + SvgPicture.asset( + 'assets/TF_logo.svg', + width: MediaQuery.of(context).size.width * 0.6, + colorFilter: ColorFilter.mode( + colorScheme.primary, + BlendMode.srcIn, + ), + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.08), + + // Title + Text( + 'Welcome to\nThreeFold Connect', + textAlign: TextAlign.center, + style: theme.textTheme.headlineLarge!.copyWith( + color: colorScheme.onSurface, + fontWeight: FontWeight.bold, + height: 1.2, + ), + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.04), + + // Description + Text( + 'Your secure gateway to the ThreeFold Grid, managing your digital identity, tokens, and more.', + textAlign: TextAlign.center, + style: theme.textTheme.bodyLarge!.copyWith( + color: colorScheme.onSurface.withOpacity(0.7), + height: 1.5, + fontSize: 16, + ), + ), + const Spacer(flex: 2), + ], + ), + ), + ), ); } } diff --git a/app/lib/screens/wizard/page2.dart b/app/lib/screens/wizard/page2.dart index 872101a51..0ba7bdbb2 100644 --- a/app/lib/screens/wizard/page2.dart +++ b/app/lib/screens/wizard/page2.dart @@ -1,19 +1,153 @@ import 'package:flutter/material.dart'; -import 'package:threebotlogin/widgets/wizard/common_page.dart'; -class Page2 extends StatelessWidget { +class Page2 extends StatefulWidget { const Page2({super.key}); + @override + State createState() => _Page2State(); +} + +class _Page2State extends State + with SingleTickerProviderStateMixin { + late AnimationController _animationController; + late Animation _fadeAnimation; + late Animation _scaleAnimation; + + @override + void initState() { + super.initState(); + _animationController = AnimationController( + duration: const Duration(milliseconds: 800), + vsync: this, + ); + + _fadeAnimation = Tween( + begin: 0.0, + end: 1.0, + ).animate(CurvedAnimation( + parent: _animationController, + curve: const Interval(0.0, 0.6, curve: Curves.easeOut), + )); + + _scaleAnimation = Tween( + begin: 0.8, + end: 1.0, + ).animate(CurvedAnimation( + parent: _animationController, + curve: const Interval(0.2, 1.0, curve: Curves.easeOut), + )); + + _animationController.forward(); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { - return const CommonPage( - title: 'MAXIMUM', - subtitle: 'SECURITY', - imagePath: 'assets/finger_outline.png', - widthPercentage: 0.6, - heightPercentage: 0.4, - description: - 'The app provides a secure authentication mechanism that creates your virtual identity on the ThreeFold Grid.', + final theme = Theme.of(context); + final colorScheme = theme.colorScheme; + + return FadeTransition( + opacity: _fadeAnimation, + child: ScaleTransition( + scale: _scaleAnimation, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Spacer(flex: 1), + + // Icon with background + Container( + width: 160, + height: 160, + decoration: BoxDecoration( + color: colorScheme.primaryContainer.withOpacity(0.3), + shape: BoxShape.circle, + ), + child: Icon( + Icons.account_balance_wallet_rounded, + size: 80, + color: colorScheme.primary, + ), + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.06), + + // Title + Text( + 'Manage Your Wallet', + textAlign: TextAlign.center, + style: theme.textTheme.headlineMedium!.copyWith( + color: colorScheme.onSurface, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.03), + + // Description + Text( + 'Send and receive ThreeFold Tokens (TFT) across multiple networks. Bridge tokens between TFChain, Stellar, and Solana.', + textAlign: TextAlign.center, + style: theme.textTheme.bodyLarge!.copyWith( + color: colorScheme.onSurface.withOpacity(0.7), + height: 1.6, + fontSize: 16, + ), + ), + + // Features list + SizedBox(height: MediaQuery.of(context).size.height * 0.04), + _buildFeatureItem( + context, + 'Multi-chain wallet support', + Icons.link_rounded, + ), + const SizedBox(height: 12), + _buildFeatureItem( + context, + 'Real-time balance tracking', + Icons.trending_up_rounded, + ), + const SizedBox(height: 12), + _buildFeatureItem( + context, + 'Secure transactions', + Icons.shield_rounded, + ), + + const Spacer(flex: 2), + ], + ), + ), + ), + ); + } + + Widget _buildFeatureItem(BuildContext context, String text, IconData icon) { + final theme = Theme.of(context); + final colorScheme = theme.colorScheme; + + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + icon, + size: 20, + color: colorScheme.primary, + ), + const SizedBox(width: 12), + Text( + text, + style: theme.textTheme.bodyMedium!.copyWith( + color: colorScheme.onSurface.withOpacity(0.8), + ), + ), + ], ); } } diff --git a/app/lib/screens/wizard/page3.dart b/app/lib/screens/wizard/page3.dart index 3a0461f4e..fd51480e0 100644 --- a/app/lib/screens/wizard/page3.dart +++ b/app/lib/screens/wizard/page3.dart @@ -1,19 +1,153 @@ import 'package:flutter/material.dart'; -import 'package:threebotlogin/widgets/wizard/common_page.dart'; -class Page3 extends StatelessWidget { +class Page3 extends StatefulWidget { const Page3({super.key}); + @override + State createState() => _Page3State(); +} + +class _Page3State extends State + with SingleTickerProviderStateMixin { + late AnimationController _animationController; + late Animation _fadeAnimation; + late Animation _scaleAnimation; + + @override + void initState() { + super.initState(); + _animationController = AnimationController( + duration: const Duration(milliseconds: 800), + vsync: this, + ); + + _fadeAnimation = Tween( + begin: 0.0, + end: 1.0, + ).animate(CurvedAnimation( + parent: _animationController, + curve: const Interval(0.0, 0.6, curve: Curves.easeOut), + )); + + _scaleAnimation = Tween( + begin: 0.8, + end: 1.0, + ).animate(CurvedAnimation( + parent: _animationController, + curve: const Interval(0.2, 1.0, curve: Curves.easeOut), + )); + + _animationController.forward(); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { - return const CommonPage( - title: 'THREEFOLD', - subtitle: 'WALLET', - imagePath: 'assets/wallet_outline.png', - description: - 'Access your ThreeFold Wallet and send/receive ThreeFold Tokens (TFT). More currencies can be added in the future.', - heightPercentage: 0.4, - widthPercentage: 0.75, + final theme = Theme.of(context); + final colorScheme = theme.colorScheme; + + return FadeTransition( + opacity: _fadeAnimation, + child: ScaleTransition( + scale: _scaleAnimation, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Spacer(flex: 1), + + // Icon with background + Container( + width: 160, + height: 160, + decoration: BoxDecoration( + color: colorScheme.primaryContainer.withOpacity(0.3), + shape: BoxShape.circle, + ), + child: Icon( + Icons.draw_rounded, + size: 80, + color: colorScheme.primary, + ), + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.06), + + // Title + Text( + 'Sign Content', + textAlign: TextAlign.center, + style: theme.textTheme.headlineMedium!.copyWith( + color: colorScheme.onSurface, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.03), + + // Description + Text( + 'Sign documents and messages securely with your wallet. Verify authenticity and maintain digital integrity.', + textAlign: TextAlign.center, + style: theme.textTheme.bodyLarge!.copyWith( + color: colorScheme.onSurface.withOpacity(0.7), + height: 1.6, + fontSize: 16, + ), + ), + + // Features list + SizedBox(height: MediaQuery.of(context).size.height * 0.04), + _buildFeatureItem( + context, + 'Cryptographic signatures', + Icons.lock_outline_rounded, + ), + const SizedBox(height: 12), + _buildFeatureItem( + context, + 'Wallet-based authentication', + Icons.vpn_key_rounded, + ), + const SizedBox(height: 12), + _buildFeatureItem( + context, + 'Verify document integrity', + Icons.verified_rounded, + ), + + const Spacer(flex: 2), + ], + ), + ), + ), + ); + } + + Widget _buildFeatureItem(BuildContext context, String text, IconData icon) { + final theme = Theme.of(context); + final colorScheme = theme.colorScheme; + + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + icon, + size: 20, + color: colorScheme.primary, + ), + const SizedBox(width: 12), + Text( + text, + style: theme.textTheme.bodyMedium!.copyWith( + color: colorScheme.onSurface.withOpacity(0.8), + ), + ), + ], ); } } diff --git a/app/lib/screens/wizard/page4.dart b/app/lib/screens/wizard/page4.dart index 1578b3704..d36261f8a 100644 --- a/app/lib/screens/wizard/page4.dart +++ b/app/lib/screens/wizard/page4.dart @@ -1,18 +1,153 @@ import 'package:flutter/material.dart'; -import 'package:threebotlogin/widgets/wizard/common_page.dart'; -class Page4 extends StatelessWidget { +class Page4 extends StatefulWidget { const Page4({super.key}); + @override + State createState() => _Page4State(); +} + +class _Page4State extends State + with SingleTickerProviderStateMixin { + late AnimationController _animationController; + late Animation _fadeAnimation; + late Animation _scaleAnimation; + + @override + void initState() { + super.initState(); + _animationController = AnimationController( + duration: const Duration(milliseconds: 800), + vsync: this, + ); + + _fadeAnimation = Tween( + begin: 0.0, + end: 1.0, + ).animate(CurvedAnimation( + parent: _animationController, + curve: const Interval(0.0, 0.6, curve: Curves.easeOut), + )); + + _scaleAnimation = Tween( + begin: 0.8, + end: 1.0, + ).animate(CurvedAnimation( + parent: _animationController, + curve: const Interval(0.2, 1.0, curve: Curves.easeOut), + )); + + _animationController.forward(); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { - return const CommonPage( - title: 'THREEFOLD', - subtitle: 'NEWS', - imagePath: 'assets/news_outline.png', - description: "Stay up to date with ThreeFold's latest news", - heightPercentage: 0.35, - widthPercentage: 0.70, + final theme = Theme.of(context); + final colorScheme = theme.colorScheme; + + return FadeTransition( + opacity: _fadeAnimation, + child: ScaleTransition( + scale: _scaleAnimation, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Spacer(flex: 1), + + // Icon with background + Container( + width: 160, + height: 160, + decoration: BoxDecoration( + color: colorScheme.primaryContainer.withOpacity(0.3), + shape: BoxShape.circle, + ), + child: Icon( + Icons.show_chart_rounded, + size: 80, + color: colorScheme.primary, + ), + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.06), + + // Title + Text( + 'Market Insights', + textAlign: TextAlign.center, + style: theme.textTheme.headlineMedium!.copyWith( + color: colorScheme.onSurface, + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: MediaQuery.of(context).size.height * 0.03), + + // Description + Text( + 'Track ThreeFold Token prices, monitor market trends, and stay informed about token performance across different networks.', + textAlign: TextAlign.center, + style: theme.textTheme.bodyLarge!.copyWith( + color: colorScheme.onSurface.withOpacity(0.7), + height: 1.6, + fontSize: 16, + ), + ), + + // Features list + SizedBox(height: MediaQuery.of(context).size.height * 0.04), + _buildFeatureItem( + context, + 'Real-time price tracking', + Icons.trending_up_rounded, + ), + const SizedBox(height: 12), + _buildFeatureItem( + context, + 'Multi-network analytics', + Icons.analytics_rounded, + ), + const SizedBox(height: 12), + _buildFeatureItem( + context, + 'Market data insights', + Icons.bar_chart_rounded, + ), + + const Spacer(flex: 2), + ], + ), + ), + ), + ); + } + + Widget _buildFeatureItem(BuildContext context, String text, IconData icon) { + final theme = Theme.of(context); + final colorScheme = theme.colorScheme; + + return Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + icon, + size: 20, + color: colorScheme.primary, + ), + const SizedBox(width: 12), + Text( + text, + style: theme.textTheme.bodyMedium!.copyWith( + color: colorScheme.onSurface.withOpacity(0.8), + ), + ), + ], ); } } diff --git a/app/lib/screens/wizard/page5.dart b/app/lib/screens/wizard/page5.dart index 546923d6b..34264fc86 100644 --- a/app/lib/screens/wizard/page5.dart +++ b/app/lib/screens/wizard/page5.dart @@ -1,18 +1,302 @@ +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:threebotlogin/widgets/wizard/common_page.dart'; +import 'package:threebotlogin/helpers/globals.dart'; +import 'package:threebotlogin/screens/wizard/web_view.dart'; +import 'package:threebotlogin/services/shared_preference_service.dart'; -class Page5 extends StatelessWidget { +class Page5 extends StatefulWidget { const Page5({super.key}); + @override + State createState() => _Page5State(); +} + +class _Page5State extends State with SingleTickerProviderStateMixin { + late AnimationController _animationController; + late Animation _fadeAnimation; + late List> _itemAnimations; + bool agreed = false; + bool attemptToContinue = false; + final termsAndConditionsUrl = Globals().termsAndConditionsUrl; + + @override + void initState() { + super.initState(); + _animationController = AnimationController( + duration: const Duration(milliseconds: 1000), + vsync: this, + ); + + _fadeAnimation = Tween( + begin: 0.0, + end: 1.0, + ).animate(CurvedAnimation( + parent: _animationController, + curve: const Interval(0.0, 0.4, curve: Curves.easeOut), + )); + + // Stagger animations for feature items + _itemAnimations = List.generate(4, (index) { + return Tween( + begin: 0.0, + end: 1.0, + ).animate(CurvedAnimation( + parent: _animationController, + curve: Interval( + 0.3 + (index * 0.12), + 0.75 + (index * 0.06), + curve: Curves.easeOut, + ), + )); + }); + + _animationController.forward(); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { - return const CommonPage( - title: 'START YOUR', - subtitle: 'JOURNEY', - imagePath: 'assets/rocket_outline.png', - heightPercentage: 0.4, - widthPercentage: 0.75, - showTermsAndConditions: true, + final theme = Theme.of(context); + final colorScheme = theme.colorScheme; + + return FadeTransition( + opacity: _fadeAnimation, + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 32), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(height: 16), + + // Title + Text( + 'Explore More', + textAlign: TextAlign.center, + style: theme.textTheme.headlineMedium!.copyWith( + color: colorScheme.onSurface, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 12), + + // Description + Text( + 'Discover the full power of ThreeFold', + textAlign: TextAlign.center, + style: theme.textTheme.bodyLarge!.copyWith( + color: colorScheme.onSurface.withOpacity(0.7), + fontSize: 16, + ), + ), + + const SizedBox(height: 24), + + // Feature grid + _buildFeatureItem( + context, + 'Farming', + 'Manage your farms and nodes', + Icons.storage_rounded, + 0, + ), + const SizedBox(height: 12), + _buildFeatureItem( + context, + 'DAO Voting', + 'Participate in governance', + Icons.how_to_vote_rounded, + 1, + ), + const SizedBox(height: 12), + _buildFeatureItem( + context, + 'Identity', + 'Verify your identity', + Icons.person_rounded, + 2, + ), + const SizedBox(height: 12), + _buildFeatureItem( + context, + 'News', + 'Stay updated with latest', + Icons.article_rounded, + 3, + ), + + const SizedBox(height: 32), + + // Terms and Conditions + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Checkbox( + value: agreed, + onChanged: (bool? value) { + agreed = value ?? false; + setState(() {}); + }, + ), + Expanded( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + children: [ + TextSpan( + text: "I agree to ThreeFold's ", + style: theme.textTheme.bodyMedium!.copyWith( + color: !agreed && attemptToContinue + ? colorScheme.error + : colorScheme.onSurface, + ), + ), + TextSpan( + text: 'Terms & Conditions.', + style: theme.textTheme.bodyMedium!.copyWith( + color: !agreed && attemptToContinue + ? colorScheme.error + : Colors.blue, + decoration: TextDecoration.underline, + decorationColor: !agreed && attemptToContinue + ? colorScheme.error + : Colors.blue, + ), + recognizer: TapGestureRecognizer() + ..onTap = () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => WebView( + title: 'Terms and Conditions', + url: termsAndConditionsUrl, + ), + ), + ); + }, + ), + ], + ), + ), + ), + ], + ), + const SizedBox(height: 16), + Center( + child: ElevatedButton( + onPressed: () async { + if (agreed) { + saveInitDone(); + Navigator.pop(context, true); + } + attemptToContinue = true; + setState(() {}); + }, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + backgroundColor: colorScheme.primary, + elevation: 0, + ), + child: Text( + "Let's Go", + style: theme.textTheme.bodyMedium!.copyWith( + color: colorScheme.onPrimary, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + + const SizedBox(height: 16), + ], + ), + ), + ), + ); + } + + Widget _buildFeatureItem( + BuildContext context, + String title, + String subtitle, + IconData icon, + int index, + ) { + final theme = Theme.of(context); + final colorScheme = theme.colorScheme; + + return FadeTransition( + opacity: _itemAnimations[index], + child: SlideTransition( + position: Tween( + begin: const Offset(0, 0.2), + end: Offset.zero, + ).animate(CurvedAnimation( + parent: _animationController, + curve: Interval( + 0.3 + (index * 0.12), + 0.75 + (index * 0.06), + curve: Curves.easeOut, + ), + )), + child: Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: colorScheme.surfaceContainer, + borderRadius: BorderRadius.circular(16), + border: Border.all( + color: colorScheme.outline.withOpacity(0.1), + ), + ), + child: Row( + children: [ + Container( + width: 48, + height: 48, + decoration: BoxDecoration( + color: colorScheme.primaryContainer.withOpacity(0.5), + borderRadius: BorderRadius.circular(12), + ), + child: Icon( + icon, + color: colorScheme.primary, + size: 24, + ), + ), + const SizedBox(width: 16), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: theme.textTheme.bodyLarge!.copyWith( + color: colorScheme.onSurface, + fontWeight: FontWeight.w600, + ), + ), + const SizedBox(height: 4), + Text( + subtitle, + style: theme.textTheme.bodySmall!.copyWith( + color: colorScheme.onSurface.withOpacity(0.6), + ), + ), + ], + ), + ), + ], + ), + ), + ), ); } } diff --git a/app/lib/screens/wizard/swipe_page.dart b/app/lib/screens/wizard/swipe_page.dart index f3e4dbb80..05ba40b68 100644 --- a/app/lib/screens/wizard/swipe_page.dart +++ b/app/lib/screens/wizard/swipe_page.dart @@ -16,8 +16,9 @@ class SwipePage extends StatefulWidget { } class _SwipePagesState extends State { - final PageController _pageController = - PageController(); // Controls the PageView + final PageController _pageController = PageController(); + int _currentPage = 0; + final int _totalPages = 5; @override void dispose() { @@ -25,60 +26,138 @@ class _SwipePagesState extends State { super.dispose(); } + void _nextPage() { + if (_currentPage < _totalPages - 1) { + _pageController.nextPage( + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + } + } + @override Widget build(BuildContext context) { + final theme = Theme.of(context); + final colorScheme = theme.colorScheme; + return Scaffold( body: Column( children: [ + // Skip button Padding( - padding: - EdgeInsets.only(top: MediaQuery.of(context).size.height * 0.01), + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), child: Row( - mainAxisAlignment: MainAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ + const SizedBox(width: 60), // Balance skip button TextButton( - onPressed: () { - showDialog( - context: context, - builder: (BuildContext context) { - return const TermsAndConditions(); - }, - ); - }, - child: Text( - 'SKIP', - style: Theme.of(context).textTheme.bodyLarge!.copyWith( - color: Theme.of(context).colorScheme.onSurface), - )) + onPressed: () { + showDialog( + context: context, + builder: (BuildContext context) { + return const TermsAndConditions(); + }, + ); + }, + child: Text( + 'Skip', + style: theme.textTheme.bodyLarge!.copyWith( + color: colorScheme.onSurface, + fontWeight: FontWeight.w500, + ), + ), + ), ], ), ), + + // Page View Expanded( child: PageView( controller: _pageController, onPageChanged: (int index) { - setState(() {}); + setState(() { + _currentPage = index; + }); }, children: const [Page1(), Page2(), Page3(), Page4(), Page5()], ), ), + + // Page Indicator Padding( - padding: const EdgeInsets.only(top: 16, bottom: 16), - child: Column( - children: [ - SmoothPageIndicator( - controller: _pageController, - count: 5, - effect: ExpandingDotsEffect( - dotWidth: 20, - dotHeight: 20, - activeDotColor: Theme.of(context).colorScheme.primary, - dotColor: Theme.of(context).colorScheme.outline, - ), - ), - ], + padding: const EdgeInsets.symmetric(vertical: 24), + child: SmoothPageIndicator( + controller: _pageController, + count: _totalPages, + effect: ExpandingDotsEffect( + dotWidth: 12, + dotHeight: 12, + spacing: 8, + activeDotColor: colorScheme.primary, + dotColor: colorScheme.outline.withOpacity(0.3), + expansionFactor: 3, + ), ), ), + + // Navigation Buttons (only show if not on last page) + if (_currentPage < _totalPages - 1) + Padding( + padding: const EdgeInsets.fromLTRB(24, 0, 24, 32), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // Previous button + if (_currentPage > 0) + OutlinedButton( + onPressed: () { + _pageController.previousPage( + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + }, + style: OutlinedButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + side: BorderSide( + color: colorScheme.outline.withOpacity(0.5), + ), + ), + child: Text( + 'Previous', + style: theme.textTheme.bodyMedium!.copyWith( + color: colorScheme.onSurface, + fontWeight: FontWeight.w600, + ), + ), + ), + if (_currentPage > 0) const SizedBox(width: 12), + + // Next button + ElevatedButton( + onPressed: _nextPage, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + backgroundColor: colorScheme.primary, + elevation: 0, + ), + child: Text( + 'Next', + style: theme.textTheme.bodyMedium!.copyWith( + color: colorScheme.onPrimary, + fontWeight: FontWeight.w600, + ), + ), + ), + ], + ), + ), ], ), );