import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:pyramid/features/auth/login_notifier.dart'; class LoginPage extends ConsumerStatefulWidget { const LoginPage({super.key}); @override ConsumerState createState() => _LoginPageState(); } class _LoginPageState extends ConsumerState { final _formKey = GlobalKey(); final _userCtrl = TextEditingController(); final _passCtrl = TextEditingController(); bool _obscure = true; @override void dispose() { _userCtrl.dispose(); _passCtrl.dispose(); super.dispose(); } Future _submit() async { if (!_formKey.currentState!.validate()) return; final homeserver = ref.read(homeserverProvider) ?? 'matrix.org'; await ref.read(loginNotifierProvider.notifier).login( username: _userCtrl.text.trim(), password: _passCtrl.text, homeserver: homeserver, ); // Redirect erfolgt reaktiv über isLoggedInProvider → Router } @override Widget build(BuildContext context) { final theme = Theme.of(context); final loginState = ref.watch(loginNotifierProvider); final loading = loginState.status == LoginStatus.loading; final homeserver = ref.watch(homeserverProvider) ?? 'matrix.org'; return Scaffold( body: Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 400), child: Padding( padding: const EdgeInsets.all(24), child: Form( key: _formKey, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Icon( Icons.change_history_rounded, size: 72, color: theme.colorScheme.primary, ), const SizedBox(height: 8), Text( 'Pyramid', textAlign: TextAlign.center, style: theme.textTheme.headlineMedium ?.copyWith(fontWeight: FontWeight.bold), ), const SizedBox(height: 4), // Server-Anzeige mit Wechsel-Link Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.dns_outlined, size: 14, color: theme.colorScheme.onSurfaceVariant), const SizedBox(width: 4), Text( homeserver, style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), const SizedBox(width: 4), GestureDetector( onTap: () => context.go('/server'), child: Text( 'ändern', style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.primary, decoration: TextDecoration.underline, ), ), ), ], ), const SizedBox(height: 32), TextFormField( controller: _userCtrl, decoration: const InputDecoration( labelText: 'Nutzername', hintText: 'dein_name', prefixIcon: Icon(Icons.person_outline), border: OutlineInputBorder(), ), autofillHints: const [AutofillHints.username], validator: (v) => (v == null || v.trim().isEmpty) ? 'Nutzername eingeben' : null, ), const SizedBox(height: 16), TextFormField( controller: _passCtrl, obscureText: _obscure, decoration: InputDecoration( labelText: 'Passwort', prefixIcon: const Icon(Icons.lock_outline), border: const OutlineInputBorder(), suffixIcon: IconButton( icon: Icon(_obscure ? Icons.visibility_outlined : Icons.visibility_off_outlined), onPressed: () => setState(() => _obscure = !_obscure), ), ), autofillHints: const [AutofillHints.password], validator: (v) => (v == null || v.isEmpty) ? 'Passwort eingeben' : null, onFieldSubmitted: (_) => _submit(), ), if (loginState.errorMessage != null) ...[ const SizedBox(height: 12), Text( loginState.errorMessage!, style: TextStyle(color: theme.colorScheme.error), textAlign: TextAlign.center, ), ], const SizedBox(height: 24), FilledButton( onPressed: loading ? null : _submit, child: loading ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator(strokeWidth: 2), ) : const Text('Anmelden'), ), ], ), ), ), ), ), ); } }