import 'package:flutter/material.dart'; import '../../core/routes.dart'; import '../../core/app_theme.dart'; class LandingPage extends StatefulWidget { const LandingPage({super.key}); @override State createState() => _LandingPageState(); } class _LandingPageState extends State { final PageController _pageController = PageController(); int _currentPage = 0; final int _numPages = 4; @override void dispose() { _pageController.dispose(); super.dispose(); } void _nextPage() { if (_currentPage < _numPages - 1) { _pageController.nextPage( duration: const Duration(milliseconds: 400), curve: Curves.easeInOut, ); } } void _skipToLast() { _pageController.animateToPage( _numPages - 1, duration: const Duration(milliseconds: 600), curve: Curves.easeInOut, ); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, body: SafeArea( child: Column( children: [ // Top Bar with Logo & Name Padding( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), child: Row( children: [ Hero( tag: "appLogo", child: Image.asset( 'assets/images/logo_jamur.png', height: 40, width: 40, fit: BoxFit.contain, ), ), const SizedBox(width: 10), const Text( "JTA Antirogo", style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppTheme.primary, ), ), const Spacer(), if (_currentPage < _numPages - 1) TextButton( onPressed: _skipToLast, child: const Text( "Lewati", style: TextStyle( color: AppTheme.textSecondary, fontWeight: FontWeight.w600, ), ), ), ], ), ), // PageView Slider Content Expanded( child: PageView( controller: _pageController, onPageChanged: (int page) { setState(() { _currentPage = page; }); }, children: [ _buildOnboardingPage( title: "Monitoring Real-Time", description: "Pantau suhu dan kelembapan kumbung jamur secara akurat dan real-time kapan saja langsung dari smartphone Anda.", illustration: _buildMonitoringIllustration(), ), _buildOnboardingPage( title: "Kontrol Cerdas", description: "Pilih Mode Otomatis dengan batas threshold cerdas atau kendalikan penyiram secara manual dengan opsi durasi waktu.", illustration: _buildControlIllustration(), ), _buildOnboardingPage( title: "Penjadwalan Presisi", description: "Atur jadwal penyiraman otomatis pada hari dan jam tertentu untuk memastikan pertumbuhan jamur tiram yang optimal.", illustration: _buildSchedulingIllustration(), ), _buildOnboardingPage( title: "Hubungkan Alat IoT", description: "Mudah dan cepat! Cukup masukkan Claim Code perangkat Anda untuk mengaktifkan pemantauan kumbung digital.", illustration: _buildConnectIllustration(), ), ], ), ), // Dot Indicators & Action Buttons Padding( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 24), child: Column( mainAxisSize: MainAxisSize.min, children: [ // Dot Indicators Row( mainAxisAlignment: MainAxisAlignment.center, children: List.generate( _numPages, (index) => _buildDot(index), ), ), const SizedBox(height: 32), // Actions area based on page index AnimatedCrossFade( firstChild: SizedBox( width: double.infinity, height: 55, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: AppTheme.primary, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30), ), ), onPressed: _nextPage, child: const Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "Lanjut", style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white, ), ), SizedBox(width: 8), Icon(Icons.arrow_forward, color: Colors.white), ], ), ), ), secondChild: Column( children: [ // LOGIN BUTTON SizedBox( width: double.infinity, height: 55, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: AppTheme.primary, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30), ), ), onPressed: () { Navigator.pushNamed(context, AppRoutes.login); }, child: const Text( "Masuk", style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: Colors.white, ), ), ), ), const SizedBox(height: 16), // REGISTER BUTTON SizedBox( width: double.infinity, height: 55, child: OutlinedButton( style: OutlinedButton.styleFrom( side: const BorderSide( color: AppTheme.primary, width: 1.5, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30), ), ), onPressed: () { Navigator.pushNamed(context, AppRoutes.register); }, child: const Text( "Belum ada akun? Daftar dulu", style: TextStyle( fontSize: 16, color: AppTheme.primary, fontWeight: FontWeight.w500, ), ), ), ), ], ), crossFadeState: _currentPage < _numPages - 1 ? CrossFadeState.showFirst : CrossFadeState.showSecond, duration: const Duration(milliseconds: 300), ), const SizedBox(height: 24), // Terms and conditions disclaimer const Text( "Dengan masuk atau mendaftar, Anda menyetujui\nKetentuan Layanan dan Kebijakan Privasi", textAlign: TextAlign.center, style: TextStyle( fontSize: 11, color: Colors.black45, ), ), ], ), ), ], ), ), ); } Widget _buildDot(int index) { final isActive = _currentPage == index; return AnimatedContainer( duration: const Duration(milliseconds: 250), margin: const EdgeInsets.symmetric(horizontal: 4), height: 8, width: isActive ? 24 : 8, decoration: BoxDecoration( color: isActive ? AppTheme.primary : AppTheme.textHint.withOpacity(0.5), borderRadius: BorderRadius.circular(4), ), ); } Widget _buildOnboardingPage({ required String title, required String description, required Widget illustration, }) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 24), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Expanded( flex: 6, child: Center( child: SingleChildScrollView( child: illustration, ), ), ), const SizedBox(height: 20), Text( title, textAlign: TextAlign.center, style: const TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: AppTheme.textPrimary, ), ), const SizedBox(height: 12), Text( description, textAlign: TextAlign.center, style: const TextStyle( fontSize: 14, color: AppTheme.textSecondary, height: 1.5, ), ), const Spacer(flex: 1), ], ), ); } // ── Illustration Widgets ────────────────────────────────────── Widget _buildIllustrationContainer({required Widget child}) { return Container( width: double.infinity, constraints: const BoxConstraints(maxWidth: 300, maxHeight: 220), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppTheme.bgPage, borderRadius: BorderRadius.circular(24), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.04), blurRadius: 16, offset: const Offset(0, 4), ), ], ), child: child, ); } Widget _buildMonitoringIllustration() { return _buildIllustrationContainer( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Row( children: [ Expanded( child: Container( padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 8), decoration: BoxDecoration( gradient: AppTheme.suhuGradient, borderRadius: BorderRadius.circular(16), ), child: const Column( children: [ Icon(Icons.thermostat, color: Colors.white, size: 28), SizedBox(height: 4), Text("Suhu", style: TextStyle(color: Colors.white70, fontSize: 11)), Text("27.8°C", style: TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold)), ], ), ), ), const SizedBox(width: 12), Expanded( child: Container( padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 8), decoration: BoxDecoration( gradient: AppTheme.humidGradient, borderRadius: BorderRadius.circular(16), ), child: const Column( children: [ Icon(Icons.water_drop, color: Colors.white, size: 28), SizedBox(height: 4), Text("Kelembapan", style: TextStyle(color: Colors.white70, fontSize: 11)), Text("86.5%", style: TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold)), ], ), ), ), ], ), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( width: 10, height: 10, decoration: const BoxDecoration( color: AppTheme.statusNormal, shape: BoxShape.circle, ), ), const SizedBox(width: 6), const Text( "Perangkat Online - Kumbung Optimal", style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: AppTheme.textPrimary, ), ), ], ), ], ), ); } Widget _buildControlIllustration() { return _buildIllustrationContainer( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // Operation Mode Card Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey.shade200), ), child: Row( children: [ const Icon(Icons.autorenew, color: AppTheme.primary, size: 24), const SizedBox(width: 8), const Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Mode Operasi", style: TextStyle(fontSize: 10, color: AppTheme.textSecondary)), Text("Otomatis (Aktif)", style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold, color: AppTheme.textPrimary)), ], ), ), Switch(value: true, onChanged: (_) {}), ], ), ), const SizedBox(height: 12), // Watering Status Card Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey.shade200), ), child: Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: AppTheme.accentLight, shape: BoxShape.circle, ), child: const Icon(Icons.shower, color: AppTheme.accent, size: 22), ), const SizedBox(width: 10), const Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Pompa Penyiraman", style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold)), Text("Menyala otomatis (30s)", style: TextStyle(fontSize: 10, color: AppTheme.textSecondary)), ], ), ), Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: AppTheme.accent, borderRadius: BorderRadius.circular(12), ), child: const Text("ON", style: TextStyle(color: Colors.white, fontSize: 10, fontWeight: FontWeight.bold)), ), ], ), ), ], ), ); } Widget _buildSchedulingIllustration() { return _buildIllustrationContainer( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ _buildScheduleRow("Penyiraman Pagi", "07:30", ["Sen", "Rab", "Jum"], true), const SizedBox(height: 10), _buildScheduleRow("Penyiraman Sore", "16:00", ["Setiap Hari"], false), ], ), ); } Widget _buildScheduleRow(String title, String time, List days, bool isActive) { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey.shade200), ), child: Row( children: [ Icon(Icons.alarm, color: isActive ? AppTheme.primary : AppTheme.textHint, size: 20), const SizedBox(width: 8), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text(title, style: const TextStyle(fontSize: 11, color: AppTheme.textSecondary)), const Spacer(), Text(time, style: const TextStyle(fontSize: 13, fontWeight: FontWeight.bold, color: AppTheme.textPrimary)), ], ), const SizedBox(height: 4), Text( days.join(', '), style: TextStyle( fontSize: 10, fontWeight: FontWeight.w500, color: isActive ? AppTheme.primaryLight : AppTheme.textHint, ), ), ], ), ), const SizedBox(width: 8), Transform.scale( scale: 0.8, child: Switch(value: isActive, onChanged: (_) {}), ), ], ), ); } Widget _buildConnectIllustration() { return _buildIllustrationContainer( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.qr_code_scanner, size: 50, color: AppTheme.primary), const SizedBox(height: 12), const Text( "Masukkan Claim Code Alat", style: TextStyle(fontSize: 13, fontWeight: FontWeight.bold, color: AppTheme.textPrimary), ), const SizedBox(height: 12), Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10), border: Border.all(color: AppTheme.primary.withOpacity(0.3), width: 1.5), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ Text( "JTA - X 9 7 A B 3", style: TextStyle( fontFamily: 'Courier', fontSize: 16, fontWeight: FontWeight.bold, color: AppTheme.primary.withOpacity(0.8), letterSpacing: 2, ), ), const SizedBox(width: 8), const Icon(Icons.check_circle, color: AppTheme.statusNormal, size: 16), ], ), ), ], ), ); } }