// Version: 1.1.0 | Created: 2026-04-05 | Updated: 2026-07-04 // Welcome/landing screen — first thing unauthenticated users see. // Two paths: join a Jitsi conference (no login) or sign in for Matrix chat. import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:go_router/go_router.dart'; class WelcomeScreen extends StatefulWidget { const WelcomeScreen({super.key}); @override State createState() => _WelcomeScreenState(); } class _WelcomeScreenState extends State { final _linkController = TextEditingController(); @override void dispose() { _linkController.dispose(); super.dispose(); } void _joinConference() { final link = _linkController.text.trim(); if (link.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Please paste a meeting link.')), ); return; } context.go('/jitsi', extra: link); } @override Widget build(BuildContext context) { final theme = Theme.of(context); final isDark = theme.brightness == Brightness.dark; return Scaffold( body: DecoratedBox( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Color(0xFF0A0F2E), Color(0xFF131A42)], ), ), child: SafeArea( child: Center( child: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 24), child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 440), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // --- Logo & tagline --- Column( children: [ SvgPicture.asset( 'assets/images/m8logo.svg', width: 80, height: 80, ), const SizedBox(height: 16), Text( 'M8Chat', style: theme.textTheme.headlineMedium?.copyWith( fontWeight: FontWeight.bold, color: theme.colorScheme.primary, ), ), const SizedBox(height: 8), Text( 'Chat and conference, all in one place', textAlign: TextAlign.center, style: theme.textTheme.bodyMedium?.copyWith( color: theme.colorScheme.onSurface.withAlpha(153), ), ), ], ), const SizedBox(height: 48), // --- Conference section --- _SectionCard( theme: theme, isDark: isDark, icon: Icons.videocam_outlined, title: 'Join a Conference', subtitle: 'Paste your meeting link to join instantly. No account needed.', child: Column( children: [ TextField( controller: _linkController, decoration: const InputDecoration( hintText: 'conf.m8chat.au/YourMeeting', prefixIcon: Icon(Icons.link), ), textInputAction: TextInputAction.go, onSubmitted: (_) => _joinConference(), ), const SizedBox(height: 12), ElevatedButton.icon( onPressed: _joinConference, icon: const Icon(Icons.videocam), label: const Text('Join Meeting'), ), ], ), ), const SizedBox(height: 20), // --- Divider --- Row( children: [ const Expanded(child: Divider()), Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Text( 'or', style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurface.withAlpha(102), ), ), ), const Expanded(child: Divider()), ], ), const SizedBox(height: 20), // --- Sign in section --- _SectionCard( theme: theme, isDark: isDark, icon: Icons.chat_bubble_outline, title: 'Sign In to Chat', subtitle: 'Access your rooms, messages and video calls.', child: OutlinedButton.icon( onPressed: () => context.go('/login'), icon: const Icon(Icons.login), label: const Text('Sign In'), style: OutlinedButton.styleFrom( minimumSize: const Size.fromHeight(52), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), side: BorderSide(color: theme.colorScheme.primary), textStyle: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, ), ), ), ), ], ), ), ), ), ), ), ); } } /// Styled card for each welcome section. class _SectionCard extends StatelessWidget { const _SectionCard({ required this.theme, required this.isDark, required this.icon, required this.title, required this.subtitle, required this.child, }); final ThemeData theme; final bool isDark; final IconData icon; final String title; final String subtitle; final Widget child; @override Widget build(BuildContext context) { return Card( child: Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(icon, color: theme.colorScheme.primary, size: 28), const SizedBox(width: 12), Expanded( child: Text( title, style: theme.textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w600, ), ), ), ], ), const SizedBox(height: 8), Text( subtitle, style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurface.withAlpha(153), ), ), const SizedBox(height: 16), child, ], ), ), ); } }