new start

This commit is contained in:
2025-10-21 21:27:23 +02:00
parent 23ecbe140c
commit 9654072b1d
31 changed files with 540 additions and 2708 deletions
@@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:hedgehog/features/auth/data/auth_repository.dart';
import 'package:hedgehog/main.dart';
class LoginScreen extends ConsumerStatefulWidget {
const LoginScreen({super.key});
@override
ConsumerState<LoginScreen> createState() => _LoginScreenState();
}
class _LoginScreenState extends ConsumerState<LoginScreen> {
final emailC = TextEditingController();
final passC = TextEditingController();
bool busy = false;
String? err;
@override
Widget build(BuildContext context) {
final auth = AuthRepository(kApiBase, ref.read(tokenStorageProvider));
return Scaffold(
appBar: AppBar(title: const Text('Login')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(children: [
TextField(
controller: emailC,
decoration: const InputDecoration(labelText: 'E-Mail')),
TextField(
controller: passC,
decoration: const InputDecoration(labelText: 'Passwort'),
obscureText: true),
if (err != null)
Text(err!, style: const TextStyle(color: Colors.red)),
const SizedBox(height: 12),
FilledButton(
onPressed: busy
? null
: () async {
setState(() => busy = true);
try {
await auth.login(emailC.text, passC.text);
if (mounted) context.go('/igel');
} catch (e) {
setState(() => err = e.toString());
} finally {
if (mounted) setState(() => busy = false);
}
},
child: const Text('Einloggen')),
TextButton(
onPressed: () => context.go('/register'),
child: const Text('Registrieren')),
])),
);
}
}
@@ -0,0 +1,85 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:hedgehog/features/auth/data/auth_repository.dart';
import 'package:hedgehog/main.dart';
class RegisterScreen extends ConsumerStatefulWidget {
const RegisterScreen({super.key});
@override
ConsumerState<RegisterScreen> createState() => _RegisterScreenState();
}
class _RegisterScreenState extends ConsumerState<RegisterScreen> {
final emailC = TextEditingController();
final passC = TextEditingController();
final confirmC = TextEditingController();
bool busy = false;
String? err;
@override
Widget build(BuildContext context) {
final auth = AuthRepository(kApiBase, ref.read(tokenStorageProvider));
return Scaffold(
appBar: AppBar(title: const Text('Registrieren')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
controller: emailC,
keyboardType: TextInputType.emailAddress,
decoration: const InputDecoration(labelText: 'E-Mail'),
),
const SizedBox(height: 12),
TextField(
controller: passC,
decoration: const InputDecoration(labelText: 'Passwort'),
obscureText: true,
),
const SizedBox(height: 12),
TextField(
controller: confirmC,
decoration: const InputDecoration(labelText: 'Passwort bestätigen'),
obscureText: true,
),
if (err != null) ...[
const SizedBox(height: 8),
Text(err!, style: const TextStyle(color: Colors.red)),
],
const SizedBox(height: 20),
FilledButton(
onPressed: busy
? null
: () async {
final email = emailC.text.trim();
final pass = passC.text;
final confirm = confirmC.text;
if (pass != confirm) {
setState(() => err = 'Passwörter stimmen nicht überein');
return;
}
setState(() => busy = true);
try {
await auth.register(email, pass);
if (mounted) context.go('/login');
} catch (e) {
setState(() => err = e.toString());
} finally {
if (mounted) setState(() => busy = false);
}
},
child: const Text('Registrieren'),
),
const SizedBox(height: 8),
TextButton(
onPressed: () => context.go('/login'),
child: const Text('Schon registriert? Zum Login'),
)
],
),
),
);
}
}