feat(auth): add AuthDialog with registration, login, code-unlock and wire into UI

This commit is contained in:
2026-09-13 21:26:57 +02:00
parent 9a8ee35fc2
commit 3b5531a9d6
5 changed files with 655 additions and 126 deletions
+96 -110
View File
@@ -1,76 +1,11 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../services/auth_service.dart';
import 'auth_dialog.dart';
class InfoScreen extends StatefulWidget {
class InfoScreen extends StatelessWidget {
const InfoScreen({super.key});
@override
State<InfoScreen> createState() => _InfoScreenState();
}
class _InfoScreenState extends State<InfoScreen> {
final TextEditingController _codeController = TextEditingController();
@override
void dispose() {
_codeController.dispose();
super.dispose();
}
void _showUnlockDialog(BuildContext context) {
showDialog(
context: context,
builder: (dialogCtx) => AlertDialog(
title: const Text('Bürgerforum-Zugang'),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Gib den Zugangscode des Bürgerforums Oggau ein, um Mängel zu melden und eigene Ideen einzubringen.',
style: TextStyle(fontSize: 13),
),
const SizedBox(height: 16),
TextField(
controller: _codeController,
obscureText: true,
decoration: const InputDecoration(
labelText: 'Zugangscode',
border: OutlineInputBorder(),
hintText: 'z.B. oggau',
),
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(dialogCtx),
child: const Text('Abbrechen'),
),
ElevatedButton(
onPressed: () async {
final auth = Provider.of<AuthService>(context, listen: false);
final success =
await auth.verifyCommunityCode(_codeController.text);
if (!dialogCtx.mounted) return;
Navigator.pop(dialogCtx);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(success
? 'Zugang erfolgreich freigeschaltet!'
: 'Ungültiger Code. Bitte wende dich an das Bürgerforum Oggau.'),
backgroundColor: success ? Colors.green : Colors.red,
),
);
},
child: const Text('Freischalten'),
),
],
),
);
}
@override
Widget build(BuildContext context) {
final auth = Provider.of<AuthService>(context);
@@ -114,57 +49,108 @@ class _InfoScreenState extends State<InfoScreen> {
),
),
const SizedBox(height: 8),
// Bürgerforum Access Status Card
// Bürgerforum Access & Account Card
Card(
color: auth.isCommunityUnlocked ? Colors.green.shade50 : Colors.blue.shade50,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
color: auth.isRegisteredUser
? Colors.green.shade50
: auth.isCommunityUnlocked
? Colors.teal.shade50
: Colors.blue.shade50,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Padding(
padding: const EdgeInsets.all(14.0),
child: Row(
child: Column(
children: [
Icon(
auth.isCommunityUnlocked
? Icons.verified_user
: Icons.lock_outline,
color: auth.isCommunityUnlocked ? Colors.green.shade700 : Colors.blue.shade800,
size: 32,
),
const SizedBox(width: 14),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
auth.isCommunityUnlocked
? 'Bürgerzugang: Aktiv'
: 'Gastmodus (Nur Lesen)',
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 15),
Row(
children: [
Icon(
auth.isRegisteredUser
? Icons.account_circle
: auth.isCommunityUnlocked
? Icons.verified_user
: Icons.lock_outline,
color: auth.isRegisteredUser
? Colors.green.shade700
: auth.isCommunityUnlocked
? Colors.teal.shade800
: Colors.blue.shade800,
size: 36,
),
const SizedBox(width: 14),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
auth.isRegisteredUser
? (auth.displayName?.isNotEmpty == true
? auth.displayName!
: 'Bürger-Konto')
: auth.isCommunityUnlocked
? 'Bürgerzugang: Aktiv (Code)'
: 'Gastmodus (Nur Lesen)',
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 15),
),
const SizedBox(height: 2),
Text(
auth.isRegisteredUser
? auth.email ?? 'Angemeldet'
: auth.isCommunityUnlocked
? 'Mängel & Ideen freigeschaltet'
: 'Anmelden oder Code eingeben zum Mitwirken.',
style: TextStyle(
fontSize: 12, color: Colors.grey.shade700),
),
],
),
const SizedBox(height: 2),
Text(
auth.isCommunityUnlocked
? 'Du kannst Mängel und Ideen einreichen.'
: 'Code eingeben, um Beiträge zu erstellen.',
style: TextStyle(
fontSize: 12, color: Colors.grey.shade700),
),
ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 14, vertical: 8),
),
],
),
onPressed: () {
if (auth.isRegisteredUser || auth.isCommunityUnlocked) {
auth.lockCommunityAccess();
} else {
AuthDialog.show(context);
}
},
child: Text(
(auth.isRegisteredUser || auth.isCommunityUnlocked)
? 'Abmelden'
: 'Anmelden',
),
),
],
),
ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
if (!auth.isRegisteredUser && auth.isCommunityUnlocked) ...[
const Divider(height: 16),
InkWell(
onTap: () => AuthDialog.show(context),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.person_add,
size: 16, color: Colors.blue.shade800),
const SizedBox(width: 6),
Text(
'Persönliches Konto anlegen für dauerhaften Login',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Colors.blue.shade800,
),
),
],
),
),
),
onPressed: () {
if (auth.isCommunityUnlocked) {
auth.lockCommunityAccess();
} else {
_showUnlockDialog(context);
}
},
child: Text(auth.isCommunityUnlocked ? 'Sperren' : 'Freischalten'),
),
],
],
),
),