Skip to content

Arquitetura

victor-kauan-coder edited this page Sep 26, 2026 · 1 revision

Arquitetura

App Android nativo em Kotlin + Jetpack Compose, uma Activity, sem backend. Reprodução com AndroidX Media3 (ExoPlayer + MediaSession).

Pacotes

com.songv.app
├── SongVApp            Application: guarda os repositórios e um escopo para gravações
├── model/              Musica, Album, Artista, Playlist, Letra, LinhaLetra
├── id3/                Id3Parser — parser ID3v2 próprio (ver "Formato das tags ID3")
├── letra/
│   ├── Lrc             parser/gerador de LRC, normalização, busca binária da linha atual
│   ├── LetraRepository escolhe a fonte da letra, busca na LRCLIB, importa .lrc
│   ├── TradutorLetra   tradução em blocos + romanização + cache em disco
│   └── Rede            HttpURLConnection mínimo (sem bibliotecas)
├── data/
│   ├── MusicaRepository    varredura do MediaStore + índice em disco
│   ├── CapaRepository      capas: disco (512 px), memória (LRU), alta resolução
│   ├── CapaProvider        entrega capas à notificação/tela de bloqueio
│   └── PreferenciasRepository  DataStore: tema, favoritas, playlists, histórico, sessão…
├── player/
│   ├── PlayerHolder        ExoPlayer + MediaSession únicos do processo
│   ├── MusicPlaybackService  MediaSessionService (notificação e foreground via Media3)
│   ├── PlayerViewModel     estado da biblioteca, fila, letra, tradução; comandos
│   └── TimerSono           timer de sono com fade-out
└── ui/
    ├── MainActivity        permissões, tema, casca com abas, player/fila sobrepostos
    ├── Navegacao           abas, pilha de telas e folhas (sobrevive à rotação)
    ├── theme/              cores, tipografia, formas
    ├── components/         capa, linhas, botões, folhas, mini player, reordenação
    └── screens/            Início, Buscar, Biblioteca, Álbum/Artista/Playlist, Player, Letra, Fila, Configurações

Fluxo de dados

flowchart LR
    MS[(MediaStore)] --> MR[MusicaRepository]
    MP3[(arquivos MP3)] --> ID3[Id3Parser]
    ID3 --> MR
    MR -->|índice em disco| MR
    MR --> VM[PlayerViewModel]
    ID3 --> LR[LetraRepository]
    LRCLIB((LRCLIB)) --> LR
    LR --> VM
    GT((Google Tradutor)) --> TR[TradutorLetra] --> VM
    VM -->|StateFlow| UI[Compose]
    UI -->|comandos| VM
    VM <--> EXO[ExoPlayer]
    EXO --- SES[MediaSession] --- SVC[MusicPlaybackService]
    SVC --> NOT[Notificação / tela de bloqueio]
    CR[CapaRepository] --> UI
    CR --> CP[CapaProvider] --> NOT
Loading

Decisões importantes

  • Um único player. PlayerHolder cria o ExoPlayer e a MediaSession uma vez por processo. A UI comanda o player direto; o serviço registra a sessão (addSession) e o Media3 cuida da notificação e de entrar em foreground só quando toca. (A 1.0 iniciava o serviço em foreground sem notificação e o sistema derrubava o app.)
  • O player é a fonte da verdade da fila. Cada item tem um mediaId único (<id>#<contador>); o ViewModel reconstrói a fila a partir da Timeline, na ordem do modo aleatório (getNextWindowIndex(..., shuffle)). Tocar a seguir e reordenar no aleatório reescrevem a ShuffleOrder.
  • Estados separados. biblioteca, reproducao, letra, preferencias e progresso são fluxos distintos. A posição (progresso) só roda enquanto alguém a observa — antes ela estava no estado geral e recompunha o app inteiro 5×/s.
  • Nada de reiniciar a música por acidente. Carregar a biblioteca é idempotente (girar a tela não recarrega) e recarregar nunca mexe na fila tocando.
  • Leitura de tags rápida. A tag é lida numa única leitura sequencial (o armazenamento compartilhado passa por FUSE; muitas leituras pequenas custavam ~1 s por arquivo). O resultado vai para files/biblioteca.json; na próxima abertura só arquivos novos/modificados são relidos.
  • Sessão. Fila, posição, ordem aleatória e repetição são salvas a cada troca de faixa, pausa, a cada 20 s tocando e ao sair; ao abrir, a fila volta pausada.

Armazenamento

O quê Onde
Preferências, favoritas, playlists, histórico, contagens, sessão, ajustes de sincronia DataStore configuracoes
Índice da biblioteca files/biblioteca.json
Letras buscadas/importadas files/letras/<id>.lrc
Traduções files/traducoes/<idioma>_<hash>.json
Capas 512 px cache/capas/ (o sistema pode limpar; são recriadas)

Clone this wiki locally