1use anyhow::Result;
2
3use crate::db::{Database, begin_immediate, get_meta, set_meta};
4
5const ONBOARDING_META_KEY: &str = "tui_onboarding_version";
6const FIRST_LAUNCH_ONBOARDING_VERSION: u32 = 1;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum OnboardingStatus {
10 Due,
11 Complete,
12 Established,
13}
14
15impl Database {
16 pub async fn onboarding_status(&self) -> Result<OnboardingStatus> {
17 let mut conn = self.acquire().await?;
18 let marker = get_meta(&mut conn, ONBOARDING_META_KEY).await?;
19 if marker_version(marker.as_deref())
20 .is_some_and(|version| version >= FIRST_LAUNCH_ONBOARDING_VERSION)
21 {
22 return Ok(OnboardingStatus::Complete);
23 }
24
25 let has_tasks: bool = sqlx::query_scalar("SELECT EXISTS(SELECT 1 FROM tasks)")
26 .fetch_one(&mut *conn)
27 .await?;
28 Ok(if has_tasks {
29 OnboardingStatus::Established
30 } else {
31 OnboardingStatus::Due
32 })
33 }
34
35 pub async fn complete_onboarding(&self) -> Result<()> {
36 let mut conn = self.acquire().await?;
37 let mut tx = begin_immediate(&mut conn).await?;
38 let marker = get_meta(&mut tx, ONBOARDING_META_KEY).await?;
39 if marker_version(marker.as_deref())
40 .is_none_or(|version| version < FIRST_LAUNCH_ONBOARDING_VERSION)
41 {
42 set_meta(
43 &mut tx,
44 ONBOARDING_META_KEY,
45 &FIRST_LAUNCH_ONBOARDING_VERSION.to_string(),
46 )
47 .await?;
48 }
49 tx.commit().await?;
50 Ok(())
51 }
52}
53
54fn marker_version(value: Option<&str>) -> Option<u32> {
55 value?.trim().parse().ok()
56}