JOGO
This commit is contained in:
256
lib/controllers/game_sharing_controller.dart
Normal file
256
lib/controllers/game_sharing_controller.dart
Normal file
@@ -0,0 +1,256 @@
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'dart:math';
|
||||
|
||||
class GameSharingController {
|
||||
final _supabase = Supabase.instance.client;
|
||||
|
||||
String get myUserId => _supabase.auth.currentUser?.id ?? '';
|
||||
String get myUserEmail => _supabase.auth.currentUser?.email ?? '';
|
||||
|
||||
// ====================================
|
||||
// 1️⃣ GERAR CÓDIGO E CRIAR SESSÃO
|
||||
// ====================================
|
||||
|
||||
Future<String?> createShareSession(String gameId) async {
|
||||
try {
|
||||
final shareCode = _generateShareCode();
|
||||
|
||||
final response = await _supabase.from('game_sessions').insert({
|
||||
'game_id': gameId,
|
||||
'created_by': myUserId,
|
||||
'share_code': shareCode,
|
||||
'status': 'active',
|
||||
}).select().single();
|
||||
|
||||
return shareCode;
|
||||
} catch (e) {
|
||||
print("❌ Erro ao criar sessão de compartilhamento: $e");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ====================================
|
||||
// 2️⃣ ENTRAR EM JOGO COMPARTILHADO
|
||||
// ====================================
|
||||
|
||||
Future<Map<String, dynamic>?> joinGameByCode(String shareCode) async {
|
||||
try {
|
||||
print("🔍 Procurando sessão com código: $shareCode");
|
||||
// Procura a sessão pelo código
|
||||
final sessions = await _supabase
|
||||
.from('game_sessions')
|
||||
.select()
|
||||
.eq('share_code', shareCode.toUpperCase())
|
||||
.eq('status', 'active');
|
||||
|
||||
print("📋 Sessões encontradas: ${sessions.length}");
|
||||
if (sessions.isEmpty) {
|
||||
print("❌ Código inválido ou expirado");
|
||||
return null;
|
||||
}
|
||||
|
||||
final session = sessions.first;
|
||||
final gameId = session['game_id'] as String;
|
||||
final createdBy = session['created_by'] as String;
|
||||
|
||||
print("🎮 Game ID: $gameId, Criado por: $createdBy");
|
||||
|
||||
// Garante que o utilizador atual tem perfil
|
||||
print("👤 Verificando perfil do utilizador: $myUserId");
|
||||
await _ensureUserProfile();
|
||||
|
||||
// Atualiza a sessão para adicionar o utilizador que está a entrar
|
||||
await _supabase.from('game_sessions').update({
|
||||
'shared_with_user_id': myUserId,
|
||||
'updated_at': DateTime.now().toIso8601String(),
|
||||
}).eq('id', session['id']);
|
||||
|
||||
print("✅ Sessão atualizada com novo utilizador");
|
||||
|
||||
// Busca informações do jogo
|
||||
final gameData = await _supabase
|
||||
.from('games')
|
||||
.select()
|
||||
.eq('id', gameId)
|
||||
.single();
|
||||
|
||||
print("📊 Dados do jogo: $gameData");
|
||||
|
||||
// Busca o nome do utilizador que criou
|
||||
final creatorData = await _supabase
|
||||
.from('profiles')
|
||||
.select('username, full_name')
|
||||
.eq('id', createdBy)
|
||||
.single();
|
||||
|
||||
print("👤 Criador: ${creatorData['full_name'] ?? creatorData['username']}");
|
||||
|
||||
return {
|
||||
'session_id': session['id'],
|
||||
'game_id': gameId,
|
||||
'creator_name': creatorData['full_name'] ?? creatorData['username'] ?? 'Utilizador',
|
||||
'game': gameData,
|
||||
};
|
||||
} catch (e) {
|
||||
print("❌ Erro ao entrar no jogo: $e");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ====================================
|
||||
// GARANTIR QUE UTILIZADOR TEM PERFIL
|
||||
// ====================================
|
||||
|
||||
Future<void> _ensureUserProfile() async {
|
||||
try {
|
||||
final user = _supabase.auth.currentUser;
|
||||
if (user == null) return;
|
||||
|
||||
// Verifica se o perfil existe
|
||||
final existing = await _supabase
|
||||
.from('profiles')
|
||||
.select()
|
||||
.eq('id', user.id)
|
||||
.maybeSingle();
|
||||
|
||||
if (existing == null) {
|
||||
// Cria o perfil se não existir - usa apenas colunas básicas
|
||||
print("📝 Criando perfil para novo utilizador");
|
||||
await _supabase.from('profiles').upsert({
|
||||
'id': user.id,
|
||||
'username': user.email?.split('@').first ?? 'user',
|
||||
}, onConflict: 'id');
|
||||
print("✅ Perfil criado com sucesso");
|
||||
} else {
|
||||
print("✅ Perfil já existe");
|
||||
}
|
||||
} catch (e) {
|
||||
print("⚠️ Aviso ao verificar/criar perfil: $e");
|
||||
// Não falha o join se o perfil já existe
|
||||
}
|
||||
}
|
||||
|
||||
// ====================================
|
||||
// 3️⃣ OBTER INFORMAÇÕES DA SESSÃO
|
||||
// ====================================
|
||||
|
||||
Future<Map<String, dynamic>?> getSessionInfo(String sessionId) async {
|
||||
try {
|
||||
final response = await _supabase
|
||||
.from('game_sessions')
|
||||
.select()
|
||||
.eq('id', sessionId)
|
||||
.single();
|
||||
|
||||
return response;
|
||||
} catch (e) {
|
||||
print("❌ Erro ao buscar informações da sessão: $e");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ====================================
|
||||
// 4️⃣ ENVIAR EVENTO DE SINCRONIZAÇÃO
|
||||
// ====================================
|
||||
|
||||
Future<bool> sendSyncEvent(
|
||||
String sessionId,
|
||||
String actionType,
|
||||
Map<String, dynamic> actionData,
|
||||
) async {
|
||||
try {
|
||||
await _supabase.from('game_sync_events').insert({
|
||||
'session_id': sessionId,
|
||||
'action_type': actionType,
|
||||
'action_data': actionData,
|
||||
'triggered_by': myUserId,
|
||||
});
|
||||
|
||||
print("✅ Evento sincronizado: $actionType");
|
||||
return true;
|
||||
} catch (e) {
|
||||
print("❌ Erro ao enviar evento de sincronização: $e");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ====================================
|
||||
// 5️⃣ OUVIR EVENTOS EM TEMPO REAL
|
||||
// ====================================
|
||||
|
||||
Stream<dynamic> listenToGameSync(String sessionId) {
|
||||
return _supabase
|
||||
.from('game_sync_events')
|
||||
.stream(primaryKey: ['id'])
|
||||
.eq('session_id', sessionId)
|
||||
.order('created_at', ascending: false);
|
||||
}
|
||||
|
||||
// ====================================
|
||||
// 6️⃣ OBTER ÚLTIMOS EVENTOS
|
||||
// ====================================
|
||||
|
||||
Future<List<Map<String, dynamic>>> getRecentSyncEvents(String sessionId, {int limit = 10}) async {
|
||||
try {
|
||||
final response = await _supabase
|
||||
.from('game_sync_events')
|
||||
.select()
|
||||
.eq('session_id', sessionId)
|
||||
.order('created_at', ascending: false)
|
||||
.limit(limit);
|
||||
|
||||
return List<Map<String, dynamic>>.from(response);
|
||||
} catch (e) {
|
||||
print("❌ Erro ao buscar eventos: $e");
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// ====================================
|
||||
// 7️⃣ TERMINAR SESSÃO COMPARTILHADA
|
||||
// ====================================
|
||||
|
||||
Future<bool> endShareSession(String sessionId) async {
|
||||
try {
|
||||
await _supabase
|
||||
.from('game_sessions')
|
||||
.update({'status': 'ended'})
|
||||
.eq('id', sessionId);
|
||||
|
||||
print("✅ Sessão terminada");
|
||||
return true;
|
||||
} catch (e) {
|
||||
print("❌ Erro ao terminar sessão: $e");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ====================================
|
||||
// 8️⃣ OBTER SESSÃO ATIVA DO JOGO
|
||||
// ====================================
|
||||
|
||||
Future<Map<String, dynamic>?> getActiveSessionForGame(String gameId) async {
|
||||
try {
|
||||
final response = await _supabase
|
||||
.from('game_sessions')
|
||||
.select()
|
||||
.eq('game_id', gameId)
|
||||
.eq('status', 'active')
|
||||
.single();
|
||||
|
||||
return response;
|
||||
} catch (e) {
|
||||
return null; // Sem sessão ativa
|
||||
}
|
||||
}
|
||||
|
||||
// ====================================
|
||||
// FUNÇÕES PRIVADAS
|
||||
// ====================================
|
||||
|
||||
String _generateShareCode() {
|
||||
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
final random = Random();
|
||||
return List.generate(6, (index) => chars[random.nextInt(chars.length)]).join();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user