import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:sighej/data/conversation_starters.dart'; import 'package:sighej/screens/profile_screen.dart'; import 'package:sighej/services/api_service.dart'; import 'package:sighej/services/session_store.dart'; bool get _bleAvailable => !kIsWeb && (defaultTargetPlatform == TargetPlatform.android || defaultTargetPlatform == TargetPlatform.iOS); const kSigHejServiceUuid = '1248f5a0-0000-1000-8000-00805f9b34fb'; const kManufacturerId = 0x4E58; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @override State createState() => _HomeScreenState(); } class _HomeScreenState extends State with SingleTickerProviderStateMixin { bool _openToTalk = false; String? _lastNudge; String? _lastStarter; late final AnimationController _pulseCtrl; late final Animation _pulseAnim; @override void initState() { super.initState(); _pulseCtrl = AnimationController( vsync: this, duration: const Duration(seconds: 2), ); _pulseAnim = Tween(begin: 1.0, end: 1.12).animate( CurvedAnimation(parent: _pulseCtrl, curve: Curves.easeInOut), ); } @override void dispose() { _pulseCtrl.dispose(); super.dispose(); } Future _toggle(SessionStore store) async { if (_openToTalk) { _pulseCtrl.stop(); _pulseCtrl.reset(); setState(() { _openToTalk = false; _lastNudge = null; _lastStarter = null; }); return; } try { await registerSession(store.bleToken, store.interests, name: store.name, tagline: store.tagline); } catch (_) {} _pulseCtrl.repeat(reverse: true); setState(() => _openToTalk = true); if (!_bleAvailable) { await Future.delayed(const Duration(seconds: 3)); if (mounted && _openToTalk) { // Demo: pick a random interest from the user's list final interests = store.interests; final matchedInterest = interests.isNotEmpty ? (interests..shuffle()).first : 'Tech'; setState(() { _lastNudge = 'Nogen i nærheden deler din interesse for $matchedInterest'; _lastStarter = getStarter(matchedInterest); }); } } } @override Widget build(BuildContext context) { final store = context.watch(); final cs = Theme.of(context).colorScheme; final isDark = Theme.of(context).brightness == Brightness.dark; return Scaffold( backgroundColor: cs.surface, body: Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 440), child: Column( children: [ // ── Top bar ────────────────────────────────────────── _TopBar(store: store), // ── Main area ──────────────────────────────────────── Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 24), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Spacer(flex: 2), // Status text AnimatedSwitcher( duration: const Duration(milliseconds: 300), child: Text( _openToTalk ? 'Du er åben for en snak' : 'Tryk for at åbne op', key: ValueKey(_openToTalk), style: Theme.of(context) .textTheme .headlineSmall ?.copyWith( fontWeight: FontWeight.w700, color: cs.onSurface), textAlign: TextAlign.center, ), ), const SizedBox(height: 8), AnimatedSwitcher( duration: const Duration(milliseconds: 300), child: Text( _openToTalk ? 'Søger efter folk med fælles interesser…' : 'Lad andre vide du er klar til en samtale', key: ValueKey('sub$_openToTalk'), style: Theme.of(context) .textTheme .bodyMedium ?.copyWith(color: cs.onSurfaceVariant), textAlign: TextAlign.center, ), ), const SizedBox(height: 48), // ── Big toggle button ───────────────────── GestureDetector( onTap: () => _toggle(store), child: ScaleTransition( scale: _openToTalk ? _pulseAnim : const AlwaysStoppedAnimation(1.0), child: Stack( alignment: Alignment.center, children: [ // Outer glow ring if (_openToTalk) Container( width: 200, height: 200, decoration: BoxDecoration( shape: BoxShape.circle, color: cs.primary.withAlpha(30), ), ), // Main circle Container( width: 168, height: 168, decoration: BoxDecoration( shape: BoxShape.circle, gradient: _openToTalk ? LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ cs.primary, Color.lerp(cs.primary, cs.secondary, 0.5)!, ], ) : LinearGradient( colors: [ cs.surfaceContainerHighest, cs.surfaceContainerHighest, ], ), boxShadow: _openToTalk ? [ BoxShadow( color: cs.primary.withAlpha(100), blurRadius: 32, spreadRadius: 4, ) ] : [ BoxShadow( color: isDark ? Colors.black45 : Colors.black12, blurRadius: 16, offset: const Offset(0, 4), ) ], ), child: Icon( _openToTalk ? Icons.waving_hand_rounded : Icons.waving_hand_outlined, size: 68, color: _openToTalk ? cs.onPrimary : cs.onSurfaceVariant, ), ), ], ), ), ), const SizedBox(height: 40), // ── Nudge card ──────────────────────────── AnimatedSwitcher( duration: const Duration(milliseconds: 400), child: _lastNudge != null ? _NudgeCard( message: _lastNudge!, starter: _lastStarter, ) : const SizedBox(height: 80), ), const Spacer(flex: 3), // ── Interest chips ──────────────────────── if (store.interests.isNotEmpty) _InterestRow(interests: store.interests), const SizedBox(height: 32), ], ), ), ), ], ), ), ), ); } } class _TopBar extends StatelessWidget { final SessionStore store; const _TopBar({required this.store}); @override Widget build(BuildContext context) { final isDark = Theme.of(context).brightness == Brightness.dark; final top = MediaQuery.of(context).padding.top; return Container( padding: EdgeInsets.fromLTRB(20, top + 12, 12, 16), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: isDark ? [const Color(0xFF1A3A40), const Color(0xFF0F2930)] : [const Color(0xFF2A9D8F), const Color(0xFF264653)], ), ), child: Row( children: [ const Icon(Icons.waving_hand, color: Colors.white, size: 22), const SizedBox(width: 8), const Text('SigHej', style: TextStyle( color: Colors.white, fontSize: 20, fontWeight: FontWeight.w800, letterSpacing: -0.5)), const Spacer(), // Display name chip Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: Colors.white.withAlpha(25), borderRadius: BorderRadius.circular(20), ), child: Text( store.displayName, style: const TextStyle( color: Colors.white, fontSize: 13, fontWeight: FontWeight.w600), ), ), const SizedBox(width: 4), IconButton( icon: const Icon(Icons.person_outline, color: Colors.white), onPressed: () => Navigator.of(context).push( MaterialPageRoute(builder: (_) => const ProfileScreen()), ), tooltip: 'Rediger profil', ), ], ), ); } } class _NudgeCard extends StatelessWidget { final String message; final String? starter; const _NudgeCard({required this.message, this.starter}); @override Widget build(BuildContext context) { final cs = Theme.of(context).colorScheme; return Container( width: double.infinity, padding: const EdgeInsets.all(20), decoration: BoxDecoration( gradient: LinearGradient( colors: [cs.primaryContainer, cs.tertiaryContainer], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: cs.primary.withAlpha(40), blurRadius: 16, offset: const Offset(0, 4), ), ], ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: 44, height: 44, decoration: BoxDecoration( color: cs.primary.withAlpha(30), borderRadius: BorderRadius.circular(12), ), child: Icon(Icons.handshake_outlined, color: cs.primary, size: 24), ), const SizedBox(width: 14), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Nogen i nærheden! 👋', style: TextStyle( fontWeight: FontWeight.w700, fontSize: 14, color: cs.onPrimaryContainer)), const SizedBox(height: 3), Text(message, style: TextStyle( fontSize: 13, color: cs.onPrimaryContainer.withAlpha(200))), if (starter != null) ...[ const SizedBox(height: 10), Container( padding: const EdgeInsets.symmetric( horizontal: 10, vertical: 7), decoration: BoxDecoration( color: cs.primary.withAlpha(20), borderRadius: BorderRadius.circular(10), border: Border.all( color: cs.primary.withAlpha(60), width: 1), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('💬 ', style: TextStyle(fontSize: 13)), Expanded( child: Text( '"$starter"', style: TextStyle( fontSize: 13, fontStyle: FontStyle.italic, color: cs.onPrimaryContainer, height: 1.4, ), ), ), ], ), ), ], ], ), ), ], ), ); } } class _InterestRow extends StatelessWidget { final List interests; const _InterestRow({required this.interests}); @override Widget build(BuildContext context) { final cs = Theme.of(context).colorScheme; return SizedBox( height: 32, child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: interests.length, separatorBuilder: (_, __) => const SizedBox(width: 6), itemBuilder: (_, i) => Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: cs.secondaryContainer, borderRadius: BorderRadius.circular(16), ), child: Text( interests[i], style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: cs.onSecondaryContainer), ), ), ), ); } }