feat: adiciona documento de progresso de implementação com status e estrutura de arquivos

This commit is contained in:
2026-02-28 13:46:32 -03:00
parent ec180e8e42
commit a588ecd382
+199
View File
@@ -0,0 +1,199 @@
# Progresso de Implementação
**Data:** 28/02/2026
**Status:** Fases 16 concluídas — compilando, testes passando, aplicação executável
**Referência:** DEVELOPMENT_PLAN.md v1.0
---
## Resumo Executivo
Todas as 6 fases do plano de desenvolvimento foram implementadas. O projeto compila sem erros,
26 testes unitários passam e a aplicação pode ser executada com `cargo run`.
---
## Status por Fase
| Fase | Descrição | Status |
|------|----------------------------------|-------------|
| 1 | Setup do projeto | ✅ Concluída |
| 2 | Domain (núcleo puro) | ✅ Concluída |
| 3 | Application (use cases + ports) | ✅ Concluída |
| 4 | Adapters (FFmpeg + filesystem) | ✅ Concluída |
| 5 | Infrastructure (processo async) | ✅ Concluída |
| 6 | UI (eframe/egui) | ✅ Concluída |
---
## Estrutura de Arquivos Criados
```
src/
├── main.rs — entrada, configuração da janela eframe
├── domain/
│ ├── mod.rs
│ ├── value_objects/
│ │ ├── mod.rs
│ │ ├── file_path.rs — FilePath (newtype sobre PathBuf)
│ │ ├── track_id.rs — TrackId (newtype opaco sobre u32)
│ │ ├── sync_offset.rs — SyncOffset (i64 ms, nunca f64)
│ │ └── track_language.rs — TrackLanguage (ISO 639-2, validado)
│ └── entities/
│ ├── mod.rs
│ ├── project.rs — Project (entidade raiz / fonte de verdade)
│ ├── video_file.rs — VideoFile
│ ├── audio_track.rs — AudioTrack
│ ├── subtitle_track.rs — SubtitleTrack
│ ├── media_track_info.rs — MediaTrackInfo + TrackKind
│ ├── mkv_output.rs — MkvOutput
│ └── track.rs — Track (enum: Audio | Subtitle)
├── application/
│ ├── mod.rs
│ ├── ports/
│ │ └── mod.rs — MediaInfoPort, MediaProcessorPort, FileSystemPort
│ └── use_cases/
│ ├── mod.rs
│ ├── load_media_info.rs — popula Project::existing_tracks via ffprobe
│ ├── add_audio_track.rs — adiciona AudioTrack ao Project
│ ├── add_subtitle.rs — adiciona SubtitleTrack ao Project
│ ├── adjust_sync.rs — altera SyncOffset de faixa externa
│ ├── edit_existing_track_sync.rs — altera SyncOffset de faixa existente
│ ├── set_track_language.rs — altera idioma de faixa externa
│ └── generate_output.rs — constrói comando e delega ao MediaProcessorPort
├── adapters/
│ ├── mod.rs
│ ├── ffmpeg/
│ │ ├── mod.rs
│ │ ├── command_builder.rs — FfmpegCommandBuilder: Project → Vec<String>
│ │ ├── ffprobe_gateway.rs — FfprobeGateway impl MediaInfoPort
│ │ └── ffmpeg_gateway.rs — FfmpegGateway impl MediaProcessorPort
│ └── filesystem/
│ ├── mod.rs — RealFileSystem impl FileSystemPort
│ └── file_picker.rs — FilePickerAdapter (diálogos nativos via rfd)
├── infrastructure/
│ ├── mod.rs
│ └── process/
│ └── mod.rs — run_ffmpeg_async (tokio), validate_dependencies()
└── ui/
├── mod.rs
├── app.rs — eframe::App; Project como única fonte de verdade
└── components/
├── mod.rs
├── video_selector.rs — seleção do vídeo base
├── output_selector.rs — seleção do arquivo de saída (.mkv)
├── existing_track_list.rs — lista faixas detectadas + edição de offset
├── add_audio_track_form.rs — formulário: áudio externo
├── add_subtitle_form.rs — formulário: legenda externa
├── sync_offset_field.rs — campo de atraso em segundos
├── language_field.rs — campo de idioma ISO 639-2
└── execution_panel.rs — botão gerar, progresso, erros
```
---
## Testes Unitários (26/26 passando)
### Domain — Value Objects
| Teste | Resultado |
|-------|-----------|
| `sync_offset::from_seconds_str_positivo``"1.2"``SyncOffset(1200)` | ✅ |
| `sync_offset::from_seconds_str_negativo``"-0.5"``SyncOffset(-500)` | ✅ |
| `sync_offset::from_seconds_str_com_sufixo_s` | ✅ |
| `sync_offset::from_seconds_str_invalido` | ✅ |
| `sync_offset::from_seconds_str_zero` | ✅ |
| `track_language::idioma_valido``"por"`, `"eng"` | ✅ |
| `track_language::idioma_invalido_curto``"pt"` | ✅ |
| `track_language::idioma_invalido_maiusculo``"POR"` | ✅ |
| `track_language::idioma_invalido_longo``"port"` | ✅ |
### Domain — Entities
| Teste | Resultado |
|-------|-----------|
| `project::projeto_valido` | ✅ |
| `project::projeto_invalido_mesmo_caminho` — output == source retorna erro | ✅ |
| `project::track_id_opaco` — TrackId não expõe indexação interna | ✅ |
### Application — Use Cases (todos com mocks, sem I/O real)
| Teste | Resultado |
|-------|-----------|
| `load_media_info::carrega_faixas_no_projeto` | ✅ |
| `add_audio_track::adiciona_audio_no_projeto` | ✅ |
| `add_subtitle::adiciona_legenda_no_projeto` | ✅ |
| `adjust_sync::ajusta_offset_existente` | ✅ |
| `adjust_sync::erro_se_id_inexistente` | ✅ |
| `edit_existing_track_sync::edita_offset_de_faixa_existente` | ✅ |
| `edit_existing_track_sync::erro_se_faixa_existente_nao_encontrada` | ✅ |
| `set_track_language::altera_idioma_da_faixa` | ✅ |
| `generate_output::sempre_inclui_c_copy` | ✅ |
### Adapters — FfmpegCommandBuilder
| Teste | Resultado |
|-------|-----------|
| `sempre_contem_c_copy` — invariante RNF-01 | ✅ |
| `output_e_o_ultimo_argumento` | ✅ |
| `itsoffset_formato_correto``1200ms``"1.200"` | ✅ |
| `mapa_faixa_externa_de_audio``map 1:a` | ✅ |
| `metadata_idioma_audio``-metadata:s:a:0 language=por` | ✅ |
---
## Dependências (Cargo.toml)
```toml
eframe = "0.27"
anyhow = "1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["process", "rt-multi-thread", "macros", "io-util", "sync"] }
rfd = "0.14"
```
---
## Invariantes Garantidas
- **`-c copy` sempre presente** — `FfmpegCommandBuilder::build()` emite incondicionalmente (RNF-01)
- **`SyncOffset` nunca usa `f64`** — armazenado como `i64` ms; conversão para string FFmpeg feita exclusivamente no `FfmpegCommandBuilder`
- **`TrackId` é opaco** — não expõe índice interno; mapeamento para `-map N:tipo` feito apenas no adapter
- **`Project` rejeita `output == source`** — validado no construtor
- **Termos FFmpeg nunca aparecem na UI** — a interface usa linguagem do usuário final
---
## O Que Falta (Backlog de Refinamento)
### Funcional
- [ ] Exibição de faixas externas adicionadas com opção de remover
- [ ] Progresso em tempo real via `run_ffmpeg_async` (infrastructure já implementada, UI usa thread bloqueante por ora)
- [ ] Exibição do comando gerado em modo debug
### Qualidade
- [ ] Testes de integração com FFmpeg real (requer ffmpeg instalado no CI)
- [ ] Testes de snapshot para o `FfmpegCommandBuilder` com projetos mais complexos
- [ ] Corrigir warnings de `unused` e `dead_code` remanescentes
### UI
- [ ] Layout responsivo mais refinado (scroll nas listas longas)
- [ ] Persistência do estado do projeto em disco (serde já disponível)
- [ ] Mensagens de erro mais amigáveis na UI
---
## Como Executar
```bash
# Verificar compilação
cargo check
# Rodar testes
cargo test
# Executar a aplicação (requer ffmpeg e ffprobe no PATH)
cargo run
```