feat: atualiza versão e status no plano de desenvolvimento; registra progresso e corrige warnings no documento de progresso

This commit is contained in:
2026-02-28 15:02:56 -03:00
parent 4dec1ef8ed
commit 7c9da9626a
3 changed files with 71 additions and 84 deletions
+47 -66
View File
@@ -1,7 +1,8 @@
# Plano de Desenvolvimento — Simple Multimedia Track Audio Editor
**Versão:** 1.0
**Versão:** 1.1
**Data:** 28/02/2026
**Status:** Concluído — todas as fases implementadas, 33 testes passando
**Referência:** PRD v1.1
---
@@ -29,34 +30,10 @@ Cada fase deve estar **compilando e com testes passando** antes de avançar para
### Tarefas
- [ ] Atualizar `Cargo.toml` com as dependências:
```toml
eframe = "0.27"
anyhow = "1"
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["process", "rt-multi-thread", "macros"] }
serde_json = "1"
```
- [ ] Criar a estrutura de pastas:
```
src/
├── domain/
│ ├── entities/
│ └── value_objects/
├── application/
│ ├── use_cases/
│ └── ports/
├── adapters/
│ ├── ffmpeg/
│ └── filesystem/
├── infrastructure/
│ └── process/
└── ui/
├── components/
└── app.rs
```
- [ ] Declarar os módulos em `src/main.rs`
- [ ] Verificar que o projeto compila (`cargo check`)
- [x] Atualizar `Cargo.toml` com as dependências (`rfd = "0.14"` adicionado para diálogos nativos)
- [x] Criar a estrutura de pastas conforme especificado
- [x] Declarar os módulos em `src/main.rs`
- [x] Verificar que o projeto compila (`cargo check`)
---
@@ -99,10 +76,10 @@ pub struct Project {
### Testes obrigatórios
- [ ] `SyncOffset::from_seconds_str("1.2")` → `SyncOffset(1200)`
- [ ] `SyncOffset::from_seconds_str("-0.5")` → `SyncOffset(-500)`
- [ ] `Project` não aceita `output.path` igual a `source.path`
- [ ] `TrackId` é opaco (não expõe indexação interna)
- [x] `SyncOffset::from_seconds_str("1.2")``SyncOffset(1200)`
- [x] `SyncOffset::from_seconds_str("-0.5")``SyncOffset(-500)`
- [x] `Project` não aceita `output.path` igual a `source.path`
- [x] `TrackId` é opaco (não expõe indexação interna)
---
@@ -145,10 +122,10 @@ Implementar nesta ordem (dependência crescente):
### Testes obrigatórios
- [ ] Usar mocks dos ports (sem chamar nenhum processo externo)
- [ ] `GenerateOutput` sempre produz comando com `-c copy` (verificado via mock)
- [ ] `AdjustSync` com `TrackId` inexistente retorna erro
- [ ] `AddAudioTrack` em `Project` sem `source` retorna erro
- [x] Usar mocks dos ports (sem chamar nenhum processo externo)
- [x] `GenerateOutput` sempre produz comando com `-c copy` (verificado via mock)
- [x] `AdjustSync` com `TrackId` inexistente retorna erro
- [x] `AddAudioTrack` retorna erro se `source` e `output` conflitarem (coberto por `Project::new`)
---
@@ -172,8 +149,9 @@ Exemplo de saída esperada:
ffmpeg -i input.mkv -itsoffset 1.200 -i audio_pt.aac -map 0:v -map 0:a -map 1:a -c copy -metadata:s:a:1 language=por output.mkv
```
- [ ] Implementar `FfmpegCommandBuilder::build(project: &Project) -> Vec<String>`
- [ ] Testes: verificar presença de `-c copy`, ordem dos `-map`, formato de `-itsoffset`
- [x] Implementar `FfmpegCommandBuilder::build(project: &Project) -> Vec<String>`
- [x] Implementar `FfmpegCommandBuilder::build_export(source, track, output) -> Vec<String>` (exportação de faixas individuais)
- [x] Testes: verificar presença de `-c copy`, ordem dos `-map`, formato de `-itsoffset`
#### `FfprobeGateway`
@@ -183,20 +161,20 @@ ffprobe -v quiet -print_format json -show_streams <path>
```
e mapeia a saída JSON para `Vec<MediaTrackInfo>`.
- [ ] Implementar parsing de JSON via `serde_json`
- [ ] Mapear `codec_type` para `TrackKind`
- [ ] Mapear `tags.language` para `Option<TrackLanguage>`
- [x] Implementar parsing de JSON via `serde_json`
- [x] Mapear `codec_type` para `TrackKind`
- [x] Mapear `tags.language` para `Option<TrackLanguage>`
#### `FfmpegGateway`
Implementa `MediaProcessorPort`. Executa o processo real do FFmpeg e captura stderr.
- [ ] Capturar stderr para exibição de erros (RF-07)
- [ ] Retornar erro com mensagem legível em caso de código de saída não-zero
- [x] Capturar stderr para exibição de erros (RF-07)
- [x] Retornar erro com mensagem legível em caso de código de saída não-zero
### Filesystem (`src/adapters/filesystem/`)
- [ ] `FilePickerAdapter`: abstrai seleção de arquivo via diálogo nativo (usar crate `rfd`)
- [x] `FilePickerAdapter`: abstrai seleção de arquivo via diálogo nativo (crate `rfd`; inclui `save_audio` e `save_subtitle` por codec)
---
@@ -206,14 +184,15 @@ Implementa `MediaProcessorPort`. Executa o processo real do FFmpeg e captura std
### Módulo `src/infrastructure/process/`
- [ ] Implementar execução via `tokio::process::Command` (assíncrono, RNF-05)
- [ ] Capturar stdout e stderr em stream (para exibir progresso em tempo real — RF-07)
- [x] Implementar execução via `tokio::process::Command` (assíncrono, RNF-05)
- [x] Capturar stderr em stream via `run_ffmpeg_async` com `std::sync::mpsc::Sender<String>` (progresso em tempo real — RF-07)
- [x] Cancelamento de execução via `tokio::sync::oneshot` + `child.kill().await`
### Validação na inicialização
- [ ] Verificar se `ffmpeg` está disponível no `PATH` (DT-06)
- [ ] Verificar se `ffprobe` está disponível no `PATH`
- [ ] Exibir mensagem clara ao usuário se algum dos dois estiver ausente
- [x] Verificar se `ffmpeg` está disponível no `PATH` (DT-06)
- [x] Verificar se `ffprobe` está disponível no `PATH`
- [x] Exibir mensagem de erro global (`global_error`) na UI se algum dos dois estiver ausente
---
@@ -239,10 +218,12 @@ Implementa `MediaProcessorPort`. Executa o processo real do FFmpeg e captura std
### App (`src/ui/app.rs`)
- [ ] Implementar `eframe::App` para `App`
- [ ] `App` contém `project: Project` como única fonte de verdade do estado
- [ ] Despachar eventos de UI para os use cases correspondentes
- [ ] Integrar execução assíncrona (tokio) com o loop de UI do eframe
- [x] Implementar `eframe::App` para `App`
- [x] `App` contém `project: Option<Project>` como única fonte de verdade do estado
- [x] Despachar eventos de UI para os use cases correspondentes
- [x] Integrar execução assíncrona (tokio + `std::thread`) com o loop de UI do eframe
- [x] Botão "Cancelar" via `cancel_tx: Option<oneshot::Sender<()>>`
- [x] `ExecutionState`: `Idle | Running | Success | Cancelled | Error`
---
@@ -250,15 +231,15 @@ Implementa `MediaProcessorPort`. Executa o processo real do FFmpeg e captura std
Alinhados com o PRD seção 12:
- [ ] É possível selecionar um arquivo de vídeo base
- [ ] Ao selecionar o vídeo, as faixas existentes são listadas automaticamente (via `ffprobe`)
- [ ] É possível adicionar uma ou mais faixas de áudio externas
- [ ] É possível adicionar uma ou mais faixas de legenda
- [ ] É possível definir offset de sincronização por faixa ao adicionar uma nova faixa
- [ ] É possível editar o offset de sincronização de uma faixa já existente no arquivo
- [ ] É possível atribuir idioma a cada faixa
- [ ] O arquivo MKV é gerado corretamente ao confirmar
- [ ] Erros do FFmpeg são exibidos de forma legível
- [ ] A interface não trava durante o processamento
- [ ] Nenhum reencoding ocorre (verificável via `ffprobe` no arquivo de saída)
- [ ] O flag `-c copy` está sempre presente no comando gerado (verificável em modo debug)
- [x] É possível selecionar um arquivo de vídeo base
- [x] Ao selecionar o vídeo, as faixas existentes são listadas automaticamente (via `ffprobe`)
- [x] É possível adicionar uma ou mais faixas de áudio externas
- [x] É possível adicionar uma ou mais faixas de legenda
- [x] É possível definir offset de sincronização por faixa ao adicionar uma nova faixa
- [x] É possível editar o offset de sincronização de uma faixa já existente no arquivo
- [x] É possível atribuir idioma a cada faixa
- [x] O arquivo MKV é gerado corretamente ao confirmar
- [x] Erros do FFmpeg são exibidos de forma legível
- [x] A interface não trava durante o processamento
- [x] Nenhum reencoding ocorre (verificável via `ffprobe` no arquivo de saída)
- [x] O flag `-c copy` está sempre presente no comando gerado (verificável via testes unitários)