feat: add AdjustExistingTrackDrift use case to adjust drift scale of existing tracks

- Implemented AdjustExistingTrackDrift struct with execute method to modify drift scale of existing tracks in a project.
- Added tests for adjusting drift scale, handling non-existent track IDs, and invalid scale values.
- Updated MediaTrackInfo and AudioTrack entities to include drift_scale field.
- Enhanced Project entity with needs_mkvmerge method to determine if mkvmerge is required based on drift scale.
- Integrated drift scale adjustments into existing track list UI, allowing users to modify drift values.
- Updated various use cases and UI components to support drift scale functionality, including add audio/subtitle forms and batch processing.
- Implemented mkvmerge availability check and integrated it into the application workflow for conditional processing.
This commit is contained in:
2026-03-01 12:01:39 -03:00
parent 285f22e2d1
commit 1ef47b3a07
31 changed files with 1081 additions and 62 deletions
+65 -1
View File
@@ -3,9 +3,13 @@ use crate::domain::value_objects::SyncOffset;
/// Campo de entrada para offset de sincronização em segundos (ex: "-1.2").
/// Converte para SyncOffset(ms) internamente ao confirmar.
/// Também suporta campo opcional de velocidade original (%) para correção de drift via mkvmerge.
pub struct SyncOffsetField {
pub raw: String,
pub error: Option<String>,
/// Percentual de velocidade original (ex: "99.983" → scale 0.99983). Padrão: "100.00".
pub drift_raw: String,
drift_error: Option<String>,
}
impl SyncOffsetField {
@@ -14,10 +18,12 @@ impl SyncOffsetField {
SyncOffsetField {
raw: format!("{:.1}", seconds),
error: None,
drift_raw: "100.00".to_string(),
drift_error: None,
}
}
/// Renderiza o campo e retorna true se o valor mudou.
/// Renderiza o campo de offset (sem o campo de drift).
pub fn ui(&mut self, ui: &mut egui::Ui, label: &str) -> bool {
let mut changed = false;
ui.horizontal(|ui| {
@@ -35,6 +41,42 @@ impl SyncOffsetField {
changed
}
/// Renderiza offset + campo de velocidade original (drift) quando `mkvmerge_available`.
///
/// - Quando `mkvmerge_available = false`: campo de velocidade é exibido desabilitado
/// com tooltip pedindo instalação do MKVToolNix.
/// - Quando `scale ≠ 1.0`: exibe aviso discreto em laranja.
pub fn ui_with_drift(&mut self, ui: &mut egui::Ui, label: &str, mkvmerge_available: bool) -> bool {
let offset_changed = self.ui(ui, label);
ui.horizontal(|ui| {
ui.label("Velocidade original (%):");
let resp = ui.add_enabled(
mkvmerge_available,
egui::TextEdit::singleline(&mut self.drift_raw).desired_width(70.0),
);
if !mkvmerge_available {
resp.on_hover_text(
"Instale MKVToolNix para usar correção de drift de velocidade.",
);
}
if let Ok(pct) = self.drift_raw.trim().parse::<f64>() {
if (pct - 100.0).abs() > 0.001 {
ui.colored_label(
egui::Color32::from_rgb(255, 160, 0),
"⚠ requer mkvmerge",
);
}
}
});
if let Some(ref err) = self.drift_error {
ui.colored_label(egui::Color32::RED, err);
}
offset_changed
}
/// Tenta converter o valor atual para SyncOffset.
pub fn parse(&mut self) -> Option<SyncOffset> {
match SyncOffset::from_seconds_str(&self.raw) {
@@ -48,4 +90,26 @@ impl SyncOffsetField {
}
}
}
/// Converte o percentual de velocidade para fator de escala (f64).
/// "100.00" → 1.0, "99.983" → 0.99983.
/// Retorna `1.0` em caso de erro (fallback seguro).
pub fn parse_drift(&mut self) -> f64 {
let trimmed = self.drift_raw.trim().trim_end_matches('%');
match trimmed.parse::<f64>() {
Ok(pct) if pct >= 1.0 && pct <= 999.99 => {
self.drift_error = None;
pct / 100.0
}
Ok(_) => {
self.drift_error =
Some("Velocidade deve estar entre 1.0% e 999.99%".to_string());
1.0
}
Err(_) => {
self.drift_error = Some("Valor inválido".to_string());
1.0
}
}
}
}