lingxia-shell 0.5.0

Shell product module and host registrations for LingXia
use crate::host::{HostCancel, HostResult, await_or_cancel};
use crate::platform_error::map_platform_error;
use lingxia_app_context::app_config;
use lingxia_platform::traits::file::{ChooseDirectoryRequest, FileService};
use lxapp::LxApp;
use serde::Serialize;
use std::path::PathBuf;
use std::sync::Arc;

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
struct AppInfo {
    product_name: String,
    version: String,
    sdk_version: String,
}

#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
struct DownloadSettingsResult {
    download_dir: String,
    uses_default_dir: bool,
    can_choose_directory: bool,
}

fn download_settings_result(app: &LxApp) -> HostResult<DownloadSettingsResult> {
    let effective = lingxia_transfer::dir(&app.app_data_dir());
    let configured = lingxia_settings::get_download_dir(&app.app_data_dir())
        .map_err(|e| lxapp::LxAppError::Runtime(e.to_string()))?;
    Ok(DownloadSettingsResult {
        download_dir: effective.to_string_lossy().to_string(),
        uses_default_dir: configured.is_none(),
        can_choose_directory: cfg!(target_os = "macos"),
    })
}

#[lingxia::host("app.getInfo")]
fn get_app_info(_app: Arc<LxApp>) -> HostResult<AppInfo> {
    let (product_name, version) = match app_config() {
        Some(cfg) => (cfg.product_name.clone(), cfg.product_version.clone()),
        None => (String::new(), String::new()),
    };
    Ok(AppInfo {
        product_name,
        version,
        sdk_version: lxapp::SDK_RUNTIME_VERSION.to_string(),
    })
}

#[lingxia::host("downloads.getSettings")]
fn get_download_settings(app: Arc<LxApp>) -> HostResult<DownloadSettingsResult> {
    download_settings_result(&app)
}

#[lingxia::host("downloads.chooseDirectory")]
async fn choose_download_directory(
    app: Arc<LxApp>,
    mut cancel: HostCancel,
) -> HostResult<DownloadSettingsResult> {
    let current_dir = lingxia_transfer::dir(&app.app_data_dir())
        .to_string_lossy()
        .to_string();
    let app_for_picker = app.clone();
    let result = await_or_cancel(&mut cancel, async move {
        app_for_picker
            .runtime
            .choose_directory(ChooseDirectoryRequest {
                title: Some("Choose Download Folder".to_string()),
                default_path: Some(current_dir),
            })
            .await
            .map_err(|e| map_platform_error("downloads.chooseDirectory", e))
    })
    .await?;

    if !result.canceled
        && let Some(path) = result.paths.first()
    {
        lingxia_transfer::set_dir(&app.app_data_dir(), PathBuf::from(path))
            .map_err(|e| lxapp::LxAppError::Runtime(e.to_string()))?;
    }

    download_settings_result(&app)
}

#[lingxia::host("downloads.resetDirectory")]
fn reset_download_directory(app: Arc<LxApp>) -> HostResult<DownloadSettingsResult> {
    lingxia_transfer::reset_dir(&app.app_data_dir())
        .map_err(|e| lxapp::LxAppError::Runtime(e.to_string()))?;
    download_settings_result(&app)
}

pub(crate) fn register() {
    crate::register_hosts![
        get_app_info,
        get_download_settings,
        choose_download_directory,
        reset_download_directory,
    ];
}