154 lines
5.5 KiB
Rust
154 lines
5.5 KiB
Rust
use eframe::egui;
|
|
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>,
|
|
/// Velocidade sugerida calculada externamente (% inteiro). Exibida como botão 💡.
|
|
suggestion_pct: Option<f64>,
|
|
}
|
|
|
|
impl SyncOffsetField {
|
|
pub fn new(initial: SyncOffset) -> Self {
|
|
let seconds = initial.as_ms() as f64 / 1000.0;
|
|
SyncOffsetField {
|
|
raw: format!("{:.1}", seconds),
|
|
error: None,
|
|
drift_raw: "100.00".to_string(),
|
|
drift_error: None,
|
|
suggestion_pct: None,
|
|
}
|
|
}
|
|
|
|
/// Define a velocidade sugerida (%) calculada a partir das durações do vídeo e da faixa.
|
|
/// `None` remove o botão de sugestão.
|
|
pub fn set_suggestion(&mut self, pct: Option<f64>) {
|
|
self.suggestion_pct = pct;
|
|
}
|
|
|
|
/// 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| {
|
|
ui.label(label);
|
|
if ui.text_edit_singleline(&mut self.raw).changed() {
|
|
changed = true;
|
|
self.error = None;
|
|
}
|
|
ui.label("s");
|
|
});
|
|
|
|
if let Some(ref err) = self.error {
|
|
ui.colored_label(egui::Color32::RED, err);
|
|
}
|
|
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.",
|
|
);
|
|
}
|
|
// Botão de sugestão calculada a partir das durações
|
|
if mkvmerge_available {
|
|
if let Some(pct) = self.suggestion_pct {
|
|
let warn = (pct - 100.0).abs() > 0.5;
|
|
let hover = format!(
|
|
"Velocidade sugerida: {:.3}%{}",
|
|
pct,
|
|
if warn {
|
|
"\n⚠ Diferença >0.5% — verifique se é o mesmo conteúdo"
|
|
} else {
|
|
" — clique para aplicar"
|
|
}
|
|
);
|
|
let color = if warn {
|
|
egui::Color32::from_rgb(255, 160, 0)
|
|
} else {
|
|
egui::Color32::from_rgb(80, 180, 80)
|
|
};
|
|
if ui
|
|
.add(egui::Button::new(
|
|
egui::RichText::new("💡").color(color).small(),
|
|
))
|
|
.on_hover_text(hover)
|
|
.clicked()
|
|
{
|
|
self.drift_raw = format!("{:.3}", pct);
|
|
}
|
|
}
|
|
}
|
|
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) {
|
|
Ok(offset) => {
|
|
self.error = None;
|
|
Some(offset)
|
|
}
|
|
Err(e) => {
|
|
self.error = Some(format!("Valor inválido: {}", e));
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 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
|
|
}
|
|
}
|
|
}
|
|
}
|