android-rust-cli 0.3.2

A CLI tool for generating Android Rust JNI templates in a single command
use crate::error::{CliError, Result};
use crate::template::{TEMPLATE_DIR, TemplateMetadata, list_templates_embedded, list_templates_fs};
use crate::ui::{self, PACKAGE};
use console::style;
use std::path::PathBuf;

pub fn list_templates(template_path: Option<PathBuf>) -> Result<()> {
    let (names, is_external) = if let Some(ref path) = template_path {
        (list_templates_fs(path)?, true)
    } else {
        (list_templates_embedded(), false)
    };

    if names.is_empty() {
        return Err(CliError::NoTemplatesFound);
    }

    ui::print_banner();
    ui::print_section_title(PACKAGE, "Available Templates");

    for name in &names {
        let metadata = get_template_metadata(name, template_path.as_ref(), is_external);

        let (description, features) = if let Some(ref m) = metadata {
            (
                m.template
                    .description
                    .clone()
                    .unwrap_or_else(|| get_fallback_description(name).to_string()),
                m.template.features.clone(),
            )
        } else {
            (get_fallback_description(name).to_string(), Vec::new())
        };

        println!("  {} {}", style("").cyan().bold(), style(name).bold());
        println!("      {}", style(&description).dim());

        if !features.is_empty() {
            let features_str = features
                .iter()
                .map(|f| format!("{}", style(f).magenta()))
                .collect::<Vec<_>>()
                .join(" ");
            println!("      {}", features_str);
        }
        println!();
    }

    println!(
        "  {}",
        style(format!("{} template(s) available", names.len())).dim()
    );
    println!();

    Ok(())
}

fn get_template_metadata(
    name: &str,
    template_path: Option<&PathBuf>,
    is_external: bool,
) -> Option<TemplateMetadata> {
    if is_external {
        if let Some(path) = template_path {
            let toml_path = path.join(name).join("template.toml");
            return TemplateMetadata::from_file(&toml_path);
        }
    } else {
        let toml_path = format!("{}/template.toml", name);
        if let Some(file) = TEMPLATE_DIR.get_file(&toml_path) {
            if let Ok(content) = std::str::from_utf8(file.contents()) {
                return TemplateMetadata::from_toml(content).ok();
            }
        }
    }
    None
}

fn get_fallback_description(name: &str) -> &'static str {
    match name {
        "standard" => "Basic Android + Rust JNI project with single module",
        "multi-module" => "Clean architecture with separate app, domain, and data modules",
        "kmp-mobile" => "Kotlin Multiplatform (Android + iOS) with Rust via JNI and C FFI",
        _ => "Custom template",
    }
}