nao aparecer para outro utilizador
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 564 KiB |
BIN
assets/playmaker-logos.png
Normal file
BIN
assets/playmaker-logos.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 MiB |
@@ -4,48 +4,49 @@ import '../models/game_model.dart';
|
|||||||
class GameController {
|
class GameController {
|
||||||
final _supabase = Supabase.instance.client;
|
final _supabase = Supabase.instance.client;
|
||||||
|
|
||||||
// 1. LER JOGOS (Stream em Tempo Real)
|
// 👇 Atalho para apanhar o ID do utilizador logado
|
||||||
|
String get myUserId => _supabase.auth.currentUser?.id ?? '';
|
||||||
|
|
||||||
|
// 1. LER JOGOS (Stream em Tempo Real da tabela original)
|
||||||
Stream<List<Game>> get gamesStream {
|
Stream<List<Game>> get gamesStream {
|
||||||
return _supabase
|
return _supabase
|
||||||
.from('games') // 1. Fica à escuta da tabela original (Garante o Tempo Real!)
|
.from('games')
|
||||||
.stream(primaryKey: ['id'])
|
.stream(primaryKey: ['id'])
|
||||||
|
.eq('user_id', myUserId) // 🔒 SEGURANÇA: Ouve apenas os jogos deste utilizador
|
||||||
.asyncMap((event) async {
|
.asyncMap((event) async {
|
||||||
// 2. Sempre que a tabela 'games' mudar (novo jogo, alteração de resultado),
|
// Lê diretamente da tabela "games" e já não da "games_with_logos"
|
||||||
// vamos buscar os dados já misturados com as imagens à nossa View.
|
final data = await _supabase
|
||||||
final viewData = await _supabase
|
.from('games')
|
||||||
.from('games_with_logos')
|
|
||||||
.select()
|
.select()
|
||||||
|
.eq('user_id', myUserId) // 🔒 SEGURANÇA
|
||||||
.order('game_date', ascending: false);
|
.order('game_date', ascending: false);
|
||||||
|
|
||||||
// 3. Convertemos para a nossa lista de objetos Game
|
return data.map((json) => Game.fromMap(json)).toList();
|
||||||
return viewData.map((json) => Game.fromMap(json)).toList();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// 👇 NOVO: LER JOGOS COM FILTROS DE EQUIPA E TEMPORADA (MANTÉM OS LOGOS)
|
// 👇 LER JOGOS COM FILTROS DE EQUIPA E TEMPORADA
|
||||||
// =========================================================================
|
|
||||||
// =========================================================================
|
|
||||||
// 👇 LER JOGOS COM FILTROS DE EQUIPA E TEMPORADA (SEM ERROS DE QUERY)
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
Stream<List<Game>> getFilteredGames({required String teamFilter, required String seasonFilter}) {
|
Stream<List<Game>> getFilteredGames({required String teamFilter, required String seasonFilter}) {
|
||||||
return _supabase
|
return _supabase
|
||||||
.from('games')
|
.from('games')
|
||||||
.stream(primaryKey: ['id'])
|
.stream(primaryKey: ['id'])
|
||||||
|
.eq('user_id', myUserId) // 🔒 SEGURANÇA
|
||||||
.asyncMap((event) async {
|
.asyncMap((event) async {
|
||||||
|
|
||||||
// 1. Começamos a query APENAS com o select (Sem o order ainda!)
|
// 1. Começamos a query na tabela principal "games"
|
||||||
var query = _supabase.from('games_with_logos').select();
|
var query = _supabase.from('games').select().eq('user_id', myUserId); // 🔒 SEGURANÇA
|
||||||
|
|
||||||
// 2. Se a temporada não for "Todas", aplicamos o filtro AQUI
|
// 2. Se a temporada não for "Todas", aplicamos o filtro AQUI
|
||||||
if (seasonFilter != 'Todas') {
|
if (seasonFilter != 'Todas') {
|
||||||
query = query.eq('season', seasonFilter);
|
query = query.eq('season', seasonFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Executamos a query e aplicamos o ORDER BY no final
|
// 3. Executamos a query e ordenamos pela data
|
||||||
final viewData = await query.order('game_date', ascending: false);
|
final data = await query.order('game_date', ascending: false);
|
||||||
|
|
||||||
List<Game> games = viewData.map((json) => Game.fromMap(json)).toList();
|
List<Game> games = data.map((json) => Game.fromMap(json)).toList();
|
||||||
|
|
||||||
// 4. Filtramos a equipa em memória
|
// 4. Filtramos a equipa em memória
|
||||||
if (teamFilter != 'Todas') {
|
if (teamFilter != 'Todas') {
|
||||||
@@ -55,21 +56,22 @@ class GameController {
|
|||||||
return games;
|
return games;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. CRIAR JOGO
|
// 2. CRIAR JOGO
|
||||||
// Retorna o ID do jogo criado para podermos navegar para o placar
|
|
||||||
Future<String?> createGame(String myTeam, String opponent, String season) async {
|
Future<String?> createGame(String myTeam, String opponent, String season) async {
|
||||||
try {
|
try {
|
||||||
final response = await _supabase.from('games').insert({
|
final response = await _supabase.from('games').insert({
|
||||||
|
'user_id': myUserId, // 🔒 CARIMBA O JOGO COM O ID DO TREINADOR
|
||||||
'my_team': myTeam,
|
'my_team': myTeam,
|
||||||
'opponent_team': opponent,
|
'opponent_team': opponent,
|
||||||
'season': season,
|
'season': season,
|
||||||
'my_score': 0,
|
'my_score': 0,
|
||||||
'opponent_score': 0,
|
'opponent_score': 0,
|
||||||
'status': 'Decorrer', // Começa como "Decorrer"
|
'status': 'Decorrer',
|
||||||
'game_date': DateTime.now().toIso8601String(),
|
'game_date': DateTime.now().toIso8601String(),
|
||||||
}).select().single(); // .select().single() retorna o objeto criado
|
}).select().single();
|
||||||
|
|
||||||
return response['id']; // Retorna o UUID gerado pelo Supabase
|
return response['id'];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Erro ao criar jogo: $e");
|
print("Erro ao criar jogo: $e");
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -11,33 +11,50 @@ class BasketTrackHeader extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
|
// Usamos um Stack para controlar a sobreposição exata
|
||||||
|
Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
// 1. A Imagem (Aumentada para 320)
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 200 * context.sf,
|
width: 320 * context.sf,
|
||||||
height: 200 * context.sf,
|
height: 350 * context.sf,
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
'assets/playmaker-logos.png',
|
'assets/playmaker-logos.png',
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// 2. O Texto "subido" para dentro da área da imagem
|
||||||
|
Positioned(
|
||||||
|
bottom: 5 * context.sf, // Ajusta este valor para aproximar/afastar do centro da logo
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'BasketTrack',
|
'BasketTrack',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 36 * context.sf,
|
fontSize: 36 * context.sf,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: Theme.of(context).colorScheme.onSurface, // 👇 Adaptável ao Modo Escuro
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 6 * context.sf),
|
SizedBox(height: 4 * context.sf),
|
||||||
Text(
|
Text(
|
||||||
'Gere as tuas equipas e estatísticas',
|
'Gere as tuas equipas e estatísticas',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16 * context.sf,
|
fontSize: 16 * context.sf,
|
||||||
color: Colors.grey, // Mantemos cinza para subtítulo
|
color: Colors.grey,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// Espaço extra para não bater nos campos de login logo a seguir
|
||||||
|
SizedBox(height: 10 * context.sf),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
pubspec.lock
16
pubspec.lock
@@ -61,10 +61,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: characters
|
name: characters
|
||||||
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
|
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.1"
|
version: "1.4.0"
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -268,18 +268,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
|
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.18"
|
version: "0.12.17"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
|
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.13.0"
|
version: "0.11.1"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -553,10 +553,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
|
sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.9"
|
version: "0.7.7"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ flutter:
|
|||||||
assets:
|
assets:
|
||||||
- assets/playmaker-logo.png
|
- assets/playmaker-logo.png
|
||||||
- assets/campo.png
|
- assets/campo.png
|
||||||
|
- assets/playmaker-logos.png
|
||||||
# An image asset can refer to one or more resolution-specific "variants", see
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
# https://flutter.dev/to/resolution-aware-images
|
# https://flutter.dev/to/resolution-aware-images
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user