feat(onboarding): guided first-run tour with background FFmpeg provisioning
Phase 5 of the 0.1.0 release prep: - FFmpeg no longer blocks startup (or crashes the app offline): provisioning runs in a background thread emitting throttled ffmpeg-progress events, with installed/downloading/failed state queryable via get_ffmpeg_status and a retry command - video jobs are invisible to claiming and tier-priority checks until FFmpeg is ready, so they wait as pending without failing — and without starving image embeddings/tagging (include_videos gating in db.rs) - 7-step show-don't-tell onboarding wizard: welcome + live FFmpeg progress, real first-folder picker, faked animating pipeline bar, placeholder gallery tiles, cycling search-syntax demo, views overview, and an AI features step with a real opt-in tagger download - skippable at every point (Escape included), persisted via settings/onboarding_completed.txt, re-runnable from Settings > General, which also gains an FFmpeg status/retry row
This commit is contained in:
@@ -2101,3 +2101,50 @@ pub async fn set_notifications_paused(app: AppHandle, paused: bool) -> Result<()
|
||||
)
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct FfmpegStatus {
|
||||
pub installed: bool,
|
||||
pub downloading: bool,
|
||||
pub failed: bool,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_ffmpeg_status() -> Result<FfmpegStatus, String> {
|
||||
Ok(FfmpegStatus {
|
||||
installed: crate::media::ffmpeg_ready(),
|
||||
downloading: crate::media::ffmpeg_downloading(),
|
||||
failed: crate::media::ffmpeg_failed(),
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn retry_ffmpeg_download(app: AppHandle) -> Result<(), String> {
|
||||
crate::media::spawn_ffmpeg_provision(app);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
const ONBOARDING_COMPLETED_FILE: &str = "settings/onboarding_completed.txt";
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_onboarding_completed(app: AppHandle) -> Result<bool, String> {
|
||||
let app_dir = app.path().app_data_dir().map_err(|e| e.to_string())?;
|
||||
let path = app_dir.join(ONBOARDING_COMPLETED_FILE);
|
||||
if !path.exists() {
|
||||
return Ok(false);
|
||||
}
|
||||
let content = std::fs::read_to_string(&path).map_err(|e| e.to_string())?;
|
||||
Ok(content.trim() == "true")
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn set_onboarding_completed(app: AppHandle, completed: bool) -> Result<(), String> {
|
||||
let app_dir = app.path().app_data_dir().map_err(|e| e.to_string())?;
|
||||
let settings_dir = app_dir.join("settings");
|
||||
std::fs::create_dir_all(&settings_dir).map_err(|e| e.to_string())?;
|
||||
std::fs::write(
|
||||
settings_dir.join("onboarding_completed.txt"),
|
||||
if completed { "true" } else { "false" },
|
||||
)
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user