import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/foundation.dart' show kIsWeb; import 'package:flutter/material.dart'; import '../theme/app_theme.dart'; import '../widgets/benefit_row.dart'; import '../widgets/google_sign_in_button.dart'; class LandingScreen extends StatefulWidget { const LandingScreen({super.key}); @override State createState() => _LandingScreenState(); } class _LandingScreenState extends State { String? _errorMessage; @override Widget build(BuildContext context) { return Scaffold( body: DecoratedBox( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ AppColors.background, Color(0xFF0C1222), Color(0xFF0A1628), ], ), ), child: Stack( children: [ const _BackgroundGlow(), SafeArea( child: LayoutBuilder( builder: (BuildContext context, BoxConstraints constraints) { final bool wide = constraints.maxWidth >= 720; return Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 960), child: wide ? _WideLayout( errorMessage: _errorMessage, onError: _handleError, ) : _NarrowLayout( errorMessage: _errorMessage, onError: _handleError, ), ), ); }, ), ), ], ), ), ); } void _handleError(Object error) { setState(() { _errorMessage = _friendlyError(error); }); } String _friendlyError(Object error) { if (error is FirebaseAuthException) { switch (error.code) { case 'unauthorized-domain': final String origin = kIsWeb ? Uri.base.origin : 'this app'; return 'Add $origin under Firebase Console → Authentication → ' 'Settings → Authorized domains.'; case 'operation-not-allowed': return 'Google sign-in is not enabled. Turn on the Google provider ' 'in Firebase Console → Authentication → Sign-in method.'; case 'popup-blocked': return 'The sign-in popup was blocked. Allow popups for this site ' 'or try again.'; case 'popup-closed-by-user': case 'cancelled-popup-request': return 'Sign-in was cancelled. Tap below to try again.'; } } final String raw = error.toString(); if (raw.contains('missing initial state') || raw.contains('sessionStorage')) { return 'This browser blocked sign-in storage (common in Firefox). ' 'Set googleWebOAuthClientId in lib/config/auth_config.dart, allow ' 'popups for this site, or try Chrome.'; } if (raw.contains('canceled') || raw.contains('cancelled')) { return 'Sign-in was cancelled. Tap below to try again.'; } if (raw.contains('network')) { return 'Network error. Check your connection and try again.'; } if (raw.contains('googleWebOAuthClientId')) { return raw.replaceFirst('Bad state: ', ''); } return 'Could not sign in. Please try again.'; } } class _BackgroundGlow extends StatelessWidget { const _BackgroundGlow(); @override Widget build(BuildContext context) { return IgnorePointer( child: Stack( children: [ Positioned( top: -120, right: -80, child: Container( width: 320, height: 320, decoration: BoxDecoration( shape: BoxShape.circle, gradient: RadialGradient( colors: [ AppColors.accent.withValues(alpha: 0.18), Colors.transparent, ], ), ), ), ), Positioned( bottom: -100, left: -60, child: Container( width: 280, height: 280, decoration: BoxDecoration( shape: BoxShape.circle, gradient: RadialGradient( colors: [ AppColors.accentMuted.withValues(alpha: 0.12), Colors.transparent, ], ), ), ), ), ], ), ); } } class _NarrowLayout extends StatelessWidget { const _NarrowLayout({required this.errorMessage, required this.onError}); final String? errorMessage; final void Function(Object error) onError; @override Widget build(BuildContext context) { return SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const _BrandHeader(), const SizedBox(height: 32), const _HeroCopy(), const SizedBox(height: 28), const _BenefitsList(), const SizedBox(height: 32), _CtaSection(errorMessage: errorMessage, onError: onError), const SizedBox(height: 24), const _TrustFooter(), ], ), ); } } class _WideLayout extends StatelessWidget { const _WideLayout({required this.errorMessage, required this.onError}); final String? errorMessage; final void Function(Object error) onError; @override Widget build(BuildContext context) { return SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 24), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Expanded( flex: 5, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _BrandHeader(), SizedBox(height: 40), _HeroCopy(), SizedBox(height: 36), _BenefitsList(), ], ), ), const SizedBox(width: 48), Expanded( flex: 4, child: _CtaCard(errorMessage: errorMessage, onError: onError), ), ], ), ); } } class _BrandHeader extends StatelessWidget { const _BrandHeader(); @override Widget build(BuildContext context) { return Row( children: [ Container( width: 40, height: 40, decoration: BoxDecoration( gradient: const LinearGradient( colors: [AppColors.accent, AppColors.accentMuted], ), borderRadius: BorderRadius.circular(10), ), child: const Icon( Icons.shield_outlined, color: AppColors.background, size: 22, ), ), const SizedBox(width: 12), Text( 'Cyber Hybrid Hub', style: Theme.of(context).textTheme.titleLarge?.copyWith( letterSpacing: -0.2, ), ), ], ); } } class _HeroCopy extends StatelessWidget { const _HeroCopy(); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: AppColors.success.withValues(alpha: 0.12), borderRadius: BorderRadius.circular(20), border: Border.all( color: AppColors.success.withValues(alpha: 0.35), ), ), child: const Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.bolt, size: 16, color: AppColors.success), SizedBox(width: 6), Text( 'Free to get started', style: TextStyle( fontSize: 13, fontWeight: FontWeight.w600, color: AppColors.success, ), ), ], ), ), const SizedBox(height: 20), Text( 'Your hybrid security\ncommand center', style: Theme.of(context).textTheme.headlineLarge, ), const SizedBox(height: 16), Text( 'Unify threat monitoring, team collaboration, and compliance ' 'workflows in one secure workspace — built for modern hybrid teams.', style: Theme.of(context).textTheme.bodyLarge?.copyWith( fontSize: 17, ), ), ], ); } } class _BenefitsList extends StatelessWidget { const _BenefitsList(); static const List<({IconData icon, String title, String subtitle})> _items = <({IconData icon, String title, String subtitle})>[ ( icon: Icons.radar, title: 'Real-time threat visibility', subtitle: 'See alerts and incidents as they happen, not hours later.', ), ( icon: Icons.groups_outlined, title: 'Built for hybrid teams', subtitle: 'On-site and remote staff share one source of truth.', ), ( icon: Icons.verified_user_outlined, title: 'Sign in securely with Google', subtitle: 'No new passwords — enterprise-ready OAuth in one tap.', ), ]; @override Widget build(BuildContext context) { return Column( children: [ for (int i = 0; i < _items.length; i++) ...[ if (i > 0) const SizedBox(height: 20), BenefitRow( icon: _items[i].icon, title: _items[i].title, subtitle: _items[i].subtitle, ), ], ], ); } } class _CtaSection extends StatelessWidget { const _CtaSection({required this.errorMessage, required this.onError}); final String? errorMessage; final void Function(Object error) onError; @override Widget build(BuildContext context) { return _CtaCard(errorMessage: errorMessage, onError: onError); } } class _CtaCard extends StatelessWidget { const _CtaCard({required this.errorMessage, required this.onError}); final String? errorMessage; final void Function(Object error) onError; @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: AppColors.surfaceElevated, borderRadius: BorderRadius.circular(16), border: Border.all(color: Colors.white.withValues(alpha: 0.08)), boxShadow: [ BoxShadow( color: AppColors.accent.withValues(alpha: 0.08), blurRadius: 40, offset: const Offset(0, 12), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( 'Get started in seconds', style: Theme.of(context).textTheme.headlineMedium?.copyWith( fontSize: 22, ), textAlign: TextAlign.center, ), const SizedBox(height: 8), Text( 'Use your Google account — no credit card required.', style: Theme.of(context).textTheme.bodyLarge, textAlign: TextAlign.center, ), const SizedBox(height: 24), if (errorMessage != null) ...[ Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Theme.of(context).colorScheme.error.withValues( alpha: 0.12, ), borderRadius: BorderRadius.circular(8), ), child: Text( errorMessage!, style: TextStyle( color: Theme.of(context).colorScheme.error, fontSize: 14, ), textAlign: TextAlign.center, ), ), const SizedBox(height: 16), ], GoogleSignInButton( label: 'Get started with Google', onError: onError, ), const SizedBox(height: 16), const _SocialProof(), ], ), ); } } class _SocialProof extends StatelessWidget { const _SocialProof(); @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.lock_outline, size: 14, color: AppColors.textSecondary), const SizedBox(width: 6), Flexible( child: Text( 'Secured by Firebase · Google OAuth', style: Theme.of(context).textTheme.bodyLarge?.copyWith(fontSize: 12), textAlign: TextAlign.center, overflow: TextOverflow.ellipsis, maxLines: 2, ), ), ], ); } } class _TrustFooter extends StatelessWidget { const _TrustFooter(); @override Widget build(BuildContext context) { return Text( 'By continuing, you agree to our Terms of Service and Privacy Policy.', style: Theme.of(context).textTheme.bodyLarge?.copyWith(fontSize: 12), textAlign: TextAlign.center, ); } }