feat: complete Phase 12 — voice playback ticker, cache, config, and UI
Add playback position ticker in event loop with 1s UI refresh rate, integrate VoiceCache for downloaded voice files, add [audio] config section (cache_size_mb, auto_download_voice), and render progress bar with waveform visualization in message bubbles. Fix race conditions in AudioPlayer: add `starting` flag to prevent false `is_stopped()` during ffplay startup, guard pid cleanup so old threads don't overwrite newer process pids. Implement `resume_from()` with ffplay `-ss` for real audio seek on unpause (-1s rewind). Kill ffplay on app exit via `stop_playback()` in shutdown + Drop impl. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,9 +7,6 @@ use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// Maximum cache size in bytes (100 MB default)
|
||||
const MAX_CACHE_SIZE_BYTES: u64 = 100 * 1024 * 1024;
|
||||
|
||||
/// Cache for voice message files
|
||||
pub struct VoiceCache {
|
||||
cache_dir: PathBuf,
|
||||
@@ -20,8 +17,8 @@ pub struct VoiceCache {
|
||||
}
|
||||
|
||||
impl VoiceCache {
|
||||
/// Creates a new VoiceCache
|
||||
pub fn new() -> Result<Self, String> {
|
||||
/// Creates a new VoiceCache with the given max size in MB
|
||||
pub fn new(max_size_mb: u64) -> Result<Self, String> {
|
||||
let cache_dir = dirs::cache_dir()
|
||||
.ok_or("Failed to get cache directory")?
|
||||
.join("tele-tui")
|
||||
@@ -34,7 +31,7 @@ impl VoiceCache {
|
||||
cache_dir,
|
||||
files: HashMap::new(),
|
||||
access_counter: 0,
|
||||
max_size_bytes: MAX_CACHE_SIZE_BYTES,
|
||||
max_size_bytes: max_size_mb * 1024 * 1024,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -123,19 +120,19 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_voice_cache_creation() {
|
||||
let cache = VoiceCache::new();
|
||||
let cache = VoiceCache::new(100);
|
||||
assert!(cache.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cache_get_nonexistent() {
|
||||
let mut cache = VoiceCache::new().unwrap();
|
||||
let mut cache = VoiceCache::new(100).unwrap();
|
||||
assert!(cache.get("nonexistent").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cache_store_and_get() {
|
||||
let mut cache = VoiceCache::new().unwrap();
|
||||
let mut cache = VoiceCache::new(100).unwrap();
|
||||
|
||||
// Create temporary file
|
||||
let temp_dir = std::env::temp_dir();
|
||||
|
||||
Reference in New Issue
Block a user