melhores marcadores adicionados

This commit is contained in:
2026-04-24 16:44:50 +01:00
parent ce16ff59b6
commit 8784cc4975
12 changed files with 789 additions and 0 deletions

32
docs/01_ARQUITETURA.md Normal file
View File

@@ -0,0 +1,32 @@
# 01 - Arquitetura de Software
A arquitetura do VdcScore foi desenhada para resolver o problema de que as origens dos dados de campeonatos locais raramente oferecem uma API oficial, em tempo real e de uso público que possa ser consumida diretamente por dezenas de aplicações clientes sem problemas de estabilidade e segurança.
## Diagrama de Fluxo (Data Flow)
```mermaid
graph TD
A[AFAVCD Web API / JSON] -->|1. Request/Scrape| B(Scraper Java)
B -->|2. Limpeza e Parsing (GSON/Jsoup)| C{Processamento}
C -->|3. Firebase Admin SDK| D[(Firebase Realtime Database)]
D -->|4. Sync Em Tempo Real| E(App Android VdcScore)
E -->|5. Exibe Dados| F[Utilizador Final]
```
## Como a Informação flui
### 1. Fonte de Dados
O sistema baseia-se nos dados provenientes do website oficial da associação (AFAVCD). Eles são obtidos essencialmente através de endpoints de "API" ocultos ou HTML bruto.
### 2. O Scraper
O **Scraper** é uma aplicação Java isolada. Esta aplicação tem de ser agendada (ex: cronjob num servidor) para correr periodicamente.
- Recolhe dados como listas de jogos (`/jorneys`), resultados, estatísticas dos clubes e plantéis (jogadores).
- Compara a nova informação, converte-a para a nossa estrutura de classes, e utiliza a biblioteca `firebase-admin` (via JSON account de serviço) para fazer update à **Firebase Realtime Database**.
- Ao usar este "middle-man" garantimos que a App Android não tem de saber lidar com a complexidade e lentidão de extrair os dados na hora (nem sobrecarregar a fonte oficial com requests de todos os utilizadores).
### 3. A Centralização (Firebase Realtime Database)
A base de dados funciona como a única fonte da verdade (*Single Source of Truth*). Os nós de dados são altamente descritivos e simples. Sempre que o Scraper faz push de dados novos, os utilizadores conectados recebem as alterações graças ao modelo de websockets da Realtime DB.
### 4. A App Cliente
A App Android está ligada diretamente à Firebase com permissões de **Leitura Apenas** (Read-Only) para a maioria das coleções (exceto para gestão de utilizadores e favoritos, caso existam).
O emparelhamento é feito via Data Models (ex: `Game.java`, `Club.java`) que correspondem *exatamente* ao formato JSON injetado pelo Scraper.

View File

@@ -0,0 +1,30 @@
# 02 - Projeto Scraper Java
A pasta irmão `scrapper` contém uma aplicação autónoma em puro Java com a responsabilidade de raspar (scrapping) a informação dos clubes, jogos e tabelas.
## Ficheiros Críticos
O projeto está implementado em `src/main/java/org/example/`. Destacam-se:
- `Main.java`: Onde o projeto arranca. Configura a ligação com Firebase, cria a Realtime DB reference e também executa as ações principais (ex. extrair info de clubes).
- `StandingsScraper.java`: Classe responsável pela extração das Tabelas Classificativas (Standings) e lista de jogos (Jornadas) baseando-se num endpoint JSON fornecido pela AFAVCD.
- `PlayersScraper.java`: Esqueleto preparado para iterar pela lista de plantéis das equipas.
- Diretório `models/`: Classes de modelos Java que refletem a estrutura exata do que será enviado ao Firebase.
## Tecnologias Usadas
1. **JSoup**: Utilizado para enviar HTTP requests a URLs tradicionais e efetuar o parsing de documentos HTML usando CSS Selectors (quando a informação não é fornecida via JSON).
2. **GSON (Google JSON)**: Utilizado quando a associação fornece endpoints JSON. O Gson pega nas "Strings" JSON devolvidas pela API e converte para objetos (models) Java, facilitando o acesso às propriedades.
3. **Firebase Admin SDK**: Ao contrário do Android (que usa Auth regular de cliente), o Scraper tem privilégios de Admin. Utiliza a "chave de serviço" de Firebase (vulgarmente no ficheiro `service-account.json` que deve manter-se sempre fora do controlo de versões, via `.gitignore`).
4. **Gradle**: O ciclo de build e os pacotes são geridos pelo Gradle (usando sintaxe `build.gradle.kts`).
## O Fluxo Padrão do Scraper
1. A função `main` carrega o Firebase Options, passando as credenciais para obter acesso total à base de dados de Firebase.
2. Invocam-se os Scrapers. Por exemplo, `StandingsScraper.scrapeAndSync()`.
3. O Scraper descarrega o payload (JSON ou HTML).
4. O Scraper itera os elementos (Equipas, Jogos). Cria uma instância da classe Model relevante (ex: `TeamStanding.java`).
5. A referência Firebase é chamada (e.g. `ref.child("Senior").child("standings")`) e o objeto é passado por `setValueAsync()`.
## Notas de Evolução
- *Limites de Rate*: Quando o projeto aumentar a sua abrangência (extrair todos os jogadores para todas as equipas), deve-se implementar delays (`Thread.sleep()`) para prevenir que o servidor que está a sofrer o scraping bloqueie o nosso IP.
- *Tipagem Ficheiros Models*: Os atributos nas classes `models/` têm de bater certo com os declarados na App Android. Qualquer refactoring a nomes de atributos, deverá ser feito em ambos os projetos sob pena de a App Android apresentar UI sem dados (`null`).

View File

@@ -0,0 +1,35 @@
# 03 - Projeto Android
O projeto principal que reside na pasta base do repositório é uma aplicação nativa Android em Java (`VdcScore_Project/VdcScore`). Esta é a interface visual que disponibiliza todos os dados extraídos pelo sistema ao utilizador final.
## Arquitetura Geral
O projeto Android adota uma arquitetura clássica recomendada pela Google baseada em pacotes funcionais com navegação moderna através do Navigation Component.
A raiz do código localiza-se em `app/src/main/java/com/example/vdcscore/`:
- **`models/`**: As classes de dados principais (`Club`, `Game`, `Jornada`, `Player`). Estes POJOs *(Plain Old Java Objects)* devem corresponder rigorosamente aos modelos utilizados no projeto Scraper, para que as bibliotecas do Firebase consigam realizar a conversão JSON-para-Objeto (`getValue(Model.class)`) automaticamente e sem falhas.
- **`ui/`**: Divide-se em vários subpacotes conforme as áreas da aplicação (Fragmentos e ViewModels associados). Encontramos pacotes como `clubs`, `definicoes`, `gallery`, `home`, `livegames`.
- **Raiz de Autenticação**: Ficheiros como `LoginActivity.java`, `CriarContaActivity.java`, `RecuperarPasswordActivity.java`, e a Activity principal de entrada do Navigation Graph (`MainActivity.java`).
## Tecnologias e Bibliotecas
A lista de dependências completas pode ser consultada em `app/build.gradle.kts`, destacando-se as seguintes bibliotecas chave:
- **ViewBinding**: Utilizado para ligação segura das views (elementos XML de layout) diretamente ao código Java, eliminando o antigo e verboso `findViewById()`.
- **Glide (`com.github.bumptech.glide:glide`)**: Responsável pelo carregamento, caching e exibição fluída de imagens remetidas por links, incluindo Logos dos clubes.
- **Firebase Auth (`libs.firebase.auth`)**: Gere o login e registo na plataforma.
- **Firebase Realtime Database (`libs.firebase.database`)**: Biblioteca principal para sincronismo de dados de leitura instantânea providenciados pelo scraper.
- **AndroidX Navigation Component**: Gere todo o fluxo de trocas de ecrã (Fragments) através do nav_graph da MainActivity.
## Componentes UI Essenciais
Muitos dos ecrãs (como listas de jogos ou classificações) funcionam à base de `RecyclerView`. Para cada lista, é criado um "Adapter" e um layout XML específico ("item layout").
## Interação com a Base de Dados
Em vários pontos (ViewModels ou diretamente nos Fragments), encontram-se instâncias de `ValueEventListener` anexadas a pontos de referência específicos do Firebase (ex: `DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Senior").child("standings");`).
Toda a atualização da UI é ativada dentro do callback `onDataChange(DataSnapshot snapshot)`.
## Notas Importantes para IA
> [!WARNING]
> Quando pedirem a um Agente de IA para alterar a UI e os cartões de exibição de dados: O Agente deverá SEMPRE verificar e ler primeiro os atributos na classe pertencente ao pacote `models` (ex: `models/Game.java`) para saber exatamente como deve fazer o set/get dos valores nas Views. Não deve inventar getters que não existam ou pressupor que a Firebase tem chaves diferentes.

View File

@@ -0,0 +1,74 @@
# 04 - Schema da Base de Dados (Firebase Realtime Database)
Este projeto utiliza o Firebase Realtime Database. Como se trata de uma base de dados NoSQL estruturada em árvore JSON, a integridade é mantida pela concordância entre o que o **Scraper Java escreve** e aquilo que a **App Android espera ler**.
A raiz da base de dados encontra-se geralmente dividida por categoria de campeonato. Assumindo como base o desenvolvimento, a organização atual reflete a estrutura de Escalões (ex. "Senior", "Junior", etc).
## Estrutura Árvore JSON (Schema Esperado)
```json
{
"Senior": {
"standings": {
"Vila Chã": {
"clubName": "Vila Chã",
"clubLogo": "https://url...",
"points": "45",
"gamesPlayed": "15",
"wins": "15",
"draws": "0",
"losses": "0",
"goalsFor": "50",
"goalsAgainst": "10",
"position": 1
},
"Outro Clube": {
...
}
},
"journeys": {
"Jornada 1": {
"games": [
{
"homeTeam": "Clube A",
"homeLogo": "https://url...",
"awayTeam": "Clube B",
"awayLogo": "https://url...",
"homeScore": "2",
"awayScore": "1",
"date": "10-10-2023",
"field": "Campo do Clube A",
"matchReportUrl": "https://url..."
}
]
}
},
"players": {
"Vila Chã": [
{
"name": "João Silva",
"number": "10",
"position": "Avançado",
"photoUrl": "https://url..."
}
]
}
},
"Users": {
"UID_12345": {
"email": "user@email.com",
"favoriteClub": "Vila Chã"
}
}
}
```
## Regras e Convenções
- **As chaves principais** (`standings`, `journeys`, `players`) devem ser escritas com letra minúscula, facilitando as queries.
- **Formatação Numérica**: Ocasionalmente no processo de Web Scraping, os valores numéricos são guardados e transmitidos como `String`. Na App Android, ao efetuar lógicas matemáticas é importante fazer parse para `Integer`. As classes `models/` ditam o tipo final.
- **Campos Opcionais**: Determinados campos como `matchReportUrl` podem vir vazios (`""`) da AFAVCD. Os adaptadores Android deverão estar preparados para ocultar botões se essa string for nula ou vazia.
## Segurança
As regras da Realtime Database (`rules.json` na consola da Firebase) deverão espelhar a permissão "Leitura de qualquer utilizador, Escrita apenas por Admin". Isto previne que um utilizador malicioso com App Adulterada envie resultados falsos.

View File

@@ -0,0 +1,96 @@
# 05 - Progresso e Estado Atual
> [!IMPORTANT]
> **Atenção IA (Agentes):** Este documento é um Registo de Progresso (Living Document). É obrigação de qualquer agente de IA atualizar este ficheiro quando terminar um conjunto de tarefas com sucesso, ou caso depare-se com impedimentos, de forma a passar contexto às próximas iterações.
## O que já foi alcançado (Abril 2026)
O projeto sofreu um esforço significativo na estabilização do **Scraper** e da interface de utilizador (UI) na **App Android**.
### No Scraper (Java)
- Foi configurada a extração das Tabelas Classificativas (Standings) e cálculos otimizados para garantir dados precisos baseados na AFAVCD.
- Alterou-se o endpoint de single-matchday para aceder a todo o calendário de época via `/jorneys` (plural endpoint).
- O Scraper está apto a recolher não apenas golos, mas todos os campos vitais de um `Game` (Jornada, Data, Campo de Jogo e URL do Relatório), enviando-os corretamente para o Firebase.
- Iniciaram-se trabalhos nos perfis dos jogadores (PlayersScraper), com mapeamento e sincronização em curso.
- A Estrutura da class `GameMatch.java` foi mantida inalterada de forma propositada durante o refactoring, para não quebrar a compatibilidade com a schema na base de dados antiga.
### Na App Android (VdcScore)
- Interface de "Jornadas" (Matchday Display UI) revista: Desenvolvidos cartões com visual premium (Card-style).
- O Data Binding no `MatchesAdapter` foi resolvido para corretamente mapear e mostrar: nomes das equipas, logótipos descarregados com `Glide`, os resultados (scores) e a informação de agendamento do jogo (Data/Campo).
- A Autenticação de base (Logins e Registos) está implementada usando o Firebase Authentication.
## Tarefas A Decorrer / Próximos Passos (TODOs)
- **Testes Finais de UI:** Garantir que quando campos opcionais do Scraper regressam a `null` (e.g. jogos ainda não marcados não têm Data), a interface Android se comporta silenciosamente (sem Crashes e apresentando estado vazio "A Definir").
- **PlayersScraper:** Completar e validar a ingestão do plantel de todos os clubes para exibir no Menu de "Equipas".
- **Sistema Offline:** Melhorar a experiência da App permitindo o Firebase cache persistir localmente quando não há acesso à Internet.
- **Push Notifications:** Quando um Scraper deteta um fim de jogo (mudança de estado para 'Terminado'), explorar a hipótese de chamar Firebase Cloud Messaging para notificar a App Android.
## Relatório de Intervenção (Desenvolvimento do Scraper de Jornadas)
**Progresso Geral Atualizado**
Foi implementada a funcionalidade para recolher e sincronizar detalhadamente todas as jornadas e jogos correspondentes. O scraper agora processa todas as informações de jornadas da API da AFAVCD e insere esses dados na Firebase Realtime Database na respetiva estrutura (`jornadas/{escalao}/{id_jornada}/{id_jogo}`), alimentando os ecrãs da App Android.
**O que foi criado ou adicionado**
- Adicionada lógica de extração e formatação ao `StandingsScraper.java` para sincronizar as jornadas com a Firebase.
- Inclusão dos campos de cada jogo com compatibilidade direta com a classe `Match.java` da App Android (`home_nome`, `away_nome`, `home_logo`, `away_logo`, `home_golos`, `away_golos`, `data`, `hora`, `campo`, `matchReportUrl`).
**O que foi modificado e porquê**
- Modificou-se o ficheiro `StandingsScraper.java` para reaproveitar a chamada de rede que já estava a ser feita ao endpoint `/jorneys`. Optou-se por introduzir a lógica neste ficheiro, pois ele já contém o mapeamento de clubes (`clubesMap`) necessário para buscar nomes e logótipos através dos IDs das equipas (`homeId`, `awayId`).
**O que foi removido**
- Nenhuma funcionalidade ou ficheiro foi removido nesta intervenção. Apenas foi expandida a capacidade do código já existente.
## Relatório de Intervenção (Desenvolvimento do Scraper de Melhores Marcadores)
**Progresso Geral Atualizado**
Foi implementada a funcionalidade para extrair e sincronizar a lista de melhores marcadores (Top Scorers) para os escalões de Seniores e Juniores. Conseguimos identificar o endpoint de "disciplina" da AFAVCD que contém os golos marcados por cada jogador em cada jornada, permitindo calcular o total acumulado.
**O que foi criado ou adicionado**
- **Novo Modelo:** Criado `TopScorer.java` no projeto Scraper para espelhar a estrutura esperada pela App Android.
- **Novo Scraper:** Criado `TopScorersScraper.java` que:
- Identifica e acede ao endpoint: `https://api.afavcd.pt/teams/modality/{id}/season/33/discipline`.
- Soma os golos de cada jogador através de todas as jornadas.
- Faz o mapeamento automático para o nome e logo do clube usando o ID da equipa.
- Ordena os marcadores por número de golos.
- Sincroniza os dados com o Firebase em `marcadores/{escalao}`.
**O que foi modificado e porquê**
- A estrutura de classes do projeto Scraper foi expandida para incluir modelos de dados mais granulares (TopScorer), facilitando a manutenção e a paridade com o projeto Android.
**O que foi removido**
- Nenhuma funcionalidade foi removida.
## Relatório de Intervenção (UI das Jornadas - App Android)
**Progresso Geral Atualizado**
As jornadas agora são carregadas e exibidas corretamente e de forma ordenada na aplicação Android (Ecrã Jornadas / GalleryFragment). A visualização dos detalhes dos jogos foi também enriquecida permitindo o acesso à "Ficha de Jogo" oficial quando o link é fornecido pelo Scraper.
**O que foi criado ou adicionado**
- Adicionado o botão "Ficha de Jogo" no layout `item_match.xml` dos cartões de jogo.
- Implementada a propriedade `matchReportUrl` (e respetivos getters/setters) no Model `Match.java` garantindo a correspondência `@PropertyName` com os dados guardados na Firebase.
- Criada a intenção (Intent) no `MatchesAdapter.java` para abrir o browser nativo e consultar o relatório da partida.
**O que foi modificado e porquê**
- O `GalleryFragment.java` foi modificado para ordenar as jornadas `matchdaysList` de forma numérica (`Collections.sort`). Isto resolveu o problema em que o Firebase devolvia as chaves ordenadas de forma alfabética (1, 10, 11, 2, 3...) baralhando a navegação sequencial no ecrã.
- O `MatchesAdapter.java` foi modificado para suportar a alternância de visibilidade do novo botão de "Ficha de Jogo" consoante a disponibilidade do URL na base de dados.
**O que foi removido**
- Nenhuma funcionalidade ou ficheiro foi removido nesta iteração, focando-se unicamente em enriquecer a experiência do utilizador.
## Relatório de Intervenção (Ecrã de Melhores Marcadores - App Android)
**Progresso Geral Atualizado**
Foi criada toda a infraestrutura base e a interface visual para acomodar os "Melhores Marcadores" da liga (Top Scorers). O ecrã foi integrado na navegação principal da App e está desenhado para alternar rapidamente entre Seniores e Juniores. Está agora perfeitamente alinhado com a árvore do Firebase `melhores_marcadores/{escalao}`, aguardando que o Scraper Java inicie a injeção de dados.
**O que foi criado ou adicionado**
- Novo Model `TopScorer.java` com as propriedades exatas esperadas (`playerName`, `playerPhoto`, `clubName`, `clubLogo`, `goals`, `position`).
- Interface de layout (`fragment_top_scorers.xml` e `item_top_scorer.xml`) com um design em formato de cartões premium, suportando a exibição da posição do jogador, foto circular do perfil, logótipo do clube e a contagem de golos.
- `TopScorersFragment.java` e `TopScorersAdapter.java` que tratam a lógica de escuta em tempo real do Firebase e fazem a ordenação pela quantidade de golos de forma descendente.
- Menu de navegação foi alargado (`mobile_navigation.xml`, `activity_main_drawer.xml`, `MainActivity.java` e `strings.xml`) para incluir a opção lateral visível e interativa "Melhores Marcadores".
**O que foi modificado e porquê**
- Adicionado ao ficheiro `themes.xml` o estilo auxiliar `ShapeAppearanceOverlay.App.CornerSize50Percent` para garantir que as fotos dos jogadores (`ShapeableImageView`) fiquem perfeitamente circulares sem recurso a bibliotecas externas complexas.
**O que foi removido**
- Nenhuma funcionalidade removida. O código consiste numa extensão (feature) 100% nova.