use crate::tui::license_utils::{LicenseCategory, LicenseInfo, RiskLevel};
use crate::tui::theme::colors;
use ratatui::prelude::*;
pub fn category_color(category: LicenseCategory) -> Color {
let scheme = colors();
match category {
LicenseCategory::Permissive | LicenseCategory::PublicDomain => scheme.success,
LicenseCategory::WeakCopyleft => scheme.info,
LicenseCategory::StrongCopyleft => scheme.warning,
LicenseCategory::NetworkCopyleft | LicenseCategory::Proprietary => scheme.error,
LicenseCategory::Unknown => scheme.text_muted,
}
}
pub fn risk_level_color(risk: RiskLevel) -> Color {
let scheme = colors();
match risk {
RiskLevel::Low => scheme.success,
RiskLevel::Medium => scheme.info,
RiskLevel::High => scheme.warning,
RiskLevel::Critical => scheme.error,
}
}
pub fn render_license_metadata_lines(
license: &str,
category: LicenseCategory,
risk_level: RiskLevel,
family: &str,
component_count: usize,
is_dual_licensed: bool,
) -> Vec<Line<'static>> {
let scheme = colors();
let mut lines = vec![];
let title = if is_dual_licensed {
format!("{license} (Dual/Multi License)")
} else {
license.to_string()
};
lines.push(Line::from(vec![Span::styled(
title,
Style::default().fg(scheme.text).bold(),
)]));
lines.push(Line::from(""));
lines.push(Line::from(vec![
Span::styled("Category: ", Style::default().fg(scheme.text_muted)),
Span::styled(
category.as_str(),
Style::default().fg(category_color(category)).bold(),
),
]));
lines.push(Line::from(vec![
Span::styled("Risk: ", Style::default().fg(scheme.text_muted)),
Span::styled(
risk_level.as_str(),
Style::default().fg(risk_level_color(risk_level)).bold(),
),
]));
lines.push(Line::from(vec![
Span::styled("Family: ", Style::default().fg(scheme.text_muted)),
Span::styled(family.to_string(), Style::default().fg(scheme.accent)),
]));
lines.push(Line::from(vec![
Span::styled("Components: ", Style::default().fg(scheme.text_muted)),
Span::styled(
component_count.to_string(),
Style::default().fg(scheme.primary),
),
]));
lines
}
pub fn get_license_characteristics(license: &str) -> Vec<(&'static str, bool)> {
let info = LicenseInfo::from_spdx(license);
match info.category {
LicenseCategory::Permissive | LicenseCategory::PublicDomain => vec![
("Commercial use allowed", true),
("Modification allowed", true),
("Distribution allowed", true),
("Patent grant", info.patent_grant),
("Copyleft/Share-alike", false),
],
LicenseCategory::StrongCopyleft | LicenseCategory::NetworkCopyleft => vec![
("Commercial use allowed", true),
("Modification allowed", true),
("Distribution allowed", true),
("Copyleft/Share-alike", true),
("Derivative work must be open", true),
],
LicenseCategory::WeakCopyleft => vec![
("Commercial use allowed", true),
("Modification allowed", true),
("Distribution allowed", true),
("Copyleft/Share-alike", true),
("Linking allowed", true),
],
LicenseCategory::Proprietary => vec![
("Commercial use allowed", false),
("Modification allowed", false),
("Distribution allowed", false),
("Source access", false),
],
LicenseCategory::Unknown => vec![("License terms unknown", false)],
}
}
pub fn render_license_characteristics_lines(license: &str) -> Vec<Line<'static>> {
let scheme = colors();
let mut lines = vec![];
lines.push(Line::styled(
"Characteristics:",
Style::default().fg(scheme.primary).bold(),
));
let characteristics = get_license_characteristics(license);
for (desc, allowed) in characteristics {
let (icon, color) = if allowed {
("✓", scheme.success)
} else {
("✗", scheme.error)
};
lines.push(Line::from(vec![
Span::styled(format!(" {icon} "), Style::default().fg(color)),
Span::raw(desc),
]));
}
let info = LicenseInfo::from_spdx(license);
if info.network_copyleft {
lines.push(Line::from(""));
lines.push(Line::from(vec![
Span::styled("⚠ ", Style::default().fg(scheme.warning)),
Span::styled(
"Network copyleft (AGPL-style)",
Style::default().fg(scheme.warning),
),
]));
}
lines
}