This commit is contained in:
2026-05-11 17:22:04 +01:00
parent 60656d77e8
commit 1e38c4ad57
9 changed files with 2386 additions and 484 deletions

View File

@@ -0,0 +1,239 @@
import 'package:flutter/material.dart';
import 'package:playmaker/classe/theme.dart';
import 'package:playmaker/controllers/game_sharing_controller.dart';
class ShareGameDialog extends StatefulWidget {
final String gameId;
final GameSharingController controller;
final String? activeSessionId;
final String? activeShareCode;
const ShareGameDialog({
super.key,
required this.gameId,
required this.controller,
this.activeSessionId,
this.activeShareCode,
});
@override
State<ShareGameDialog> createState() => _ShareGameDialogState();
}
class _ShareGameDialogState extends State<ShareGameDialog> {
String? _shareCode;
bool _isLoading = false;
String? _error;
@override
void initState() {
super.initState();
_shareCode = widget.activeShareCode;
}
Future<void> _createSession() async {
setState(() {
_error = null;
_isLoading = true;
});
final code = await widget.controller.createShareSession(widget.gameId);
if (!mounted) return;
setState(() {
_isLoading = false;
if (code == null) {
_error = 'Erro ao criar sessão. Tenta novamente.';
} else {
_shareCode = code;
}
});
if (_shareCode != null && widget.activeSessionId == null) {
final session = await widget.controller.getActiveSessionForGame(
widget.gameId,
);
if (session != null && mounted) {
Navigator.of(
context,
).pop({'session_id': session['id'], 'share_code': _shareCode});
}
}
}
@override
Widget build(BuildContext context) {
return AlertDialog(
backgroundColor: Theme.of(context).colorScheme.surface,
title: Text(
'Partilhar Jogo',
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.bold,
),
),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (_shareCode != null) ...[
Text(
'Código de partilha:',
style: TextStyle(color: Theme.of(context).colorScheme.onSurface),
),
const SizedBox(height: 10),
SelectableText(
_shareCode!,
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: AppTheme.primaryRed,
),
),
const SizedBox(height: 10),
Text(
'Envie este código ao seu parceiro e peça que ele entre no jogo.',
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.8),
),
),
] else ...[
Text(
'Crie um código e partilhe o jogo com outro utilizador.',
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.8),
),
),
],
if (_error != null) ...[
const SizedBox(height: 10),
Text(_error!, style: const TextStyle(color: Colors.red)),
],
],
),
actions: [
TextButton(
onPressed: _isLoading ? null : () => Navigator.of(context).pop(),
child: const Text('Fechar'),
),
if (_shareCode == null)
TextButton(
onPressed: _isLoading ? null : _createSession,
child: _isLoading
? const SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Text('Criar código'),
)
else
TextButton(
onPressed: () {
Navigator.of(context).pop({
'session_id': widget.activeSessionId,
'share_code': _shareCode,
});
},
child: const Text('OK'),
),
],
);
}
}
class JoinGameDialog extends StatefulWidget {
final GameSharingController controller;
const JoinGameDialog({super.key, required this.controller});
@override
State<JoinGameDialog> createState() => _JoinGameDialogState();
}
class _JoinGameDialogState extends State<JoinGameDialog> {
final TextEditingController _codeController = TextEditingController();
bool _isLoading = false;
String? _error;
Future<void> _joinSession() async {
setState(() {
_isLoading = true;
_error = null;
});
final result = await widget.controller.joinGameByCode(
_codeController.text.trim(),
);
if (!mounted) return;
setState(() {
_isLoading = false;
});
if (result == null) {
setState(() {
_error = 'Código inválido ou sessão não disponível.';
});
return;
}
Navigator.of(context).pop(result);
}
@override
Widget build(BuildContext context) {
return AlertDialog(
backgroundColor: Theme.of(context).colorScheme.surface,
title: Text(
'Entrar em Jogo Partilhado',
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface,
fontWeight: FontWeight.bold,
),
),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Digite o código enviado pelo outro utilizador.',
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface.withOpacity(0.8),
),
),
const SizedBox(height: 16),
TextField(
controller: _codeController,
textCapitalization: TextCapitalization.characters,
decoration: InputDecoration(
labelText: 'Código',
border: const OutlineInputBorder(),
hintText: 'ABC123',
),
),
if (_error != null) ...[
const SizedBox(height: 12),
Text(_error!, style: const TextStyle(color: Colors.red)),
],
],
),
actions: [
TextButton(
onPressed: _isLoading ? null : () => Navigator.of(context).pop(),
child: const Text('Cancelar'),
),
TextButton(
onPressed: _isLoading ? null : _joinSession,
child: _isLoading
? const SizedBox(
width: 18,
height: 18,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Text('Entrar'),
),
],
);
}
}