Release v0.8.1 #206
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "iccery",
|
"name": "iccery",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.7.4",
|
"version": "0.8.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"fetch-argyll": "node scripts/fetch-argyll.mjs",
|
"fetch-argyll": "node scripts/fetch-argyll.mjs",
|
||||||
|
|||||||
Generated
+1
-1
@@ -1423,7 +1423,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iccery"
|
name = "iccery"
|
||||||
version = "0.8.0"
|
version = "0.8.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"image",
|
"image",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "iccery"
|
name = "iccery"
|
||||||
version = "0.8.0"
|
version = "0.8.1"
|
||||||
description = "Modern Printer Profiling UI frontend for ArgyllCMS"
|
description = "Modern Printer Profiling UI frontend for ArgyllCMS"
|
||||||
authors = ["Gordon"]
|
authors = ["Gordon"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
@@ -829,11 +829,13 @@ pub async fn read_tiff_preview_png(path: String) -> Result<String, String> {
|
|||||||
Ok(base64::engine::general_purpose::STANDARD.encode(png_bytes.into_inner()))
|
Ok(base64::engine::general_purpose::STANDARD.encode(png_bytes.into_inner()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||||
pub struct ChartreadConfig {
|
pub struct ChartreadConfig {
|
||||||
pub basename: String,
|
pub basename: String,
|
||||||
pub cwd: String,
|
pub cwd: String,
|
||||||
pub port: Option<String>,
|
pub port: Option<String>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub enable_i1pro2_leds: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_chartread_args(config: &ChartreadConfig) -> Vec<String> {
|
pub fn build_chartread_args(config: &ChartreadConfig) -> Vec<String> {
|
||||||
@@ -849,6 +851,11 @@ pub fn build_chartread_args(config: &ChartreadConfig) -> Vec<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.enable_i1pro2_leds.unwrap_or(false) {
|
||||||
|
args.push("-Y".to_string());
|
||||||
|
args.push("l".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
args.push(config.basename.clone());
|
args.push(config.basename.clone());
|
||||||
args
|
args
|
||||||
}
|
}
|
||||||
@@ -857,8 +864,12 @@ pub fn build_chartread_args(config: &ChartreadConfig) -> Vec<String> {
|
|||||||
pub async fn run_chartread(
|
pub async fn run_chartread(
|
||||||
app: AppHandle,
|
app: AppHandle,
|
||||||
state: State<'_, ProcessManager>,
|
state: State<'_, ProcessManager>,
|
||||||
config: ChartreadConfig,
|
mut config: ChartreadConfig,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
|
if config.enable_i1pro2_leds.is_none() {
|
||||||
|
let settings = crate::settings::load_settings(app.clone()).unwrap_or_default();
|
||||||
|
config.enable_i1pro2_leds = Some(settings.enable_i1pro2_leds);
|
||||||
|
}
|
||||||
let binary = resolve_binary(app.clone(), "chartread".to_string()).await?;
|
let binary = resolve_binary(app.clone(), "chartread".to_string()).await?;
|
||||||
let args = build_chartread_args(&config);
|
let args = build_chartread_args(&config);
|
||||||
let id = format!("chartread_{}", config.basename);
|
let id = format!("chartread_{}", config.basename);
|
||||||
@@ -1558,6 +1569,7 @@ mod tests {
|
|||||||
basename: "my_profile".to_string(),
|
basename: "my_profile".to_string(),
|
||||||
cwd: "/home/user".to_string(),
|
cwd: "/home/user".to_string(),
|
||||||
port: None,
|
port: None,
|
||||||
|
enable_i1pro2_leds: None,
|
||||||
};
|
};
|
||||||
let args = build_chartread_args(&config);
|
let args = build_chartread_args(&config);
|
||||||
assert_eq!(args, vec!["-v", "-u", "my_profile"]);
|
assert_eq!(args, vec!["-v", "-u", "my_profile"]);
|
||||||
@@ -1569,6 +1581,7 @@ mod tests {
|
|||||||
basename: "my_profile".to_string(),
|
basename: "my_profile".to_string(),
|
||||||
cwd: "/home/user".to_string(),
|
cwd: "/home/user".to_string(),
|
||||||
port: Some("".to_string()),
|
port: Some("".to_string()),
|
||||||
|
enable_i1pro2_leds: None,
|
||||||
};
|
};
|
||||||
let args = build_chartread_args(&config);
|
let args = build_chartread_args(&config);
|
||||||
assert_eq!(args, vec!["-v", "-u", "my_profile"]);
|
assert_eq!(args, vec!["-v", "-u", "my_profile"]);
|
||||||
@@ -1580,11 +1593,48 @@ mod tests {
|
|||||||
basename: "my_profile".to_string(),
|
basename: "my_profile".to_string(),
|
||||||
cwd: "/home/user".to_string(),
|
cwd: "/home/user".to_string(),
|
||||||
port: Some("1".to_string()),
|
port: Some("1".to_string()),
|
||||||
|
enable_i1pro2_leds: None,
|
||||||
};
|
};
|
||||||
let args = build_chartread_args(&config);
|
let args = build_chartread_args(&config);
|
||||||
assert_eq!(args, vec!["-v", "-u", "-c", "1", "my_profile"]);
|
assert_eq!(args, vec!["-v", "-u", "-c", "1", "my_profile"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_build_chartread_args_leds_enabled() {
|
||||||
|
let config = ChartreadConfig {
|
||||||
|
basename: "my_profile".to_string(),
|
||||||
|
cwd: "/home/user".to_string(),
|
||||||
|
port: None,
|
||||||
|
enable_i1pro2_leds: Some(true),
|
||||||
|
};
|
||||||
|
let args = build_chartread_args(&config);
|
||||||
|
assert_eq!(args, vec!["-v", "-u", "-Y", "l", "my_profile"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_build_chartread_args_with_port_and_leds() {
|
||||||
|
let config = ChartreadConfig {
|
||||||
|
basename: "my_profile".to_string(),
|
||||||
|
cwd: "/home/user".to_string(),
|
||||||
|
port: Some("1".to_string()),
|
||||||
|
enable_i1pro2_leds: Some(true),
|
||||||
|
};
|
||||||
|
let args = build_chartread_args(&config);
|
||||||
|
assert_eq!(args, vec!["-v", "-u", "-c", "1", "-Y", "l", "my_profile"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_build_chartread_args_leds_disabled() {
|
||||||
|
let config = ChartreadConfig {
|
||||||
|
basename: "my_profile".to_string(),
|
||||||
|
cwd: "/home/user".to_string(),
|
||||||
|
port: None,
|
||||||
|
enable_i1pro2_leds: Some(false),
|
||||||
|
};
|
||||||
|
let args = build_chartread_args(&config);
|
||||||
|
assert_eq!(args, vec!["-v", "-u", "my_profile"]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_build_average_args() {
|
fn test_build_average_args() {
|
||||||
let config = AverageConfig {
|
let config = AverageConfig {
|
||||||
|
|||||||
@@ -74,6 +74,8 @@ pub struct AppSettings {
|
|||||||
pub delta_e_warning_max: f64,
|
pub delta_e_warning_max: f64,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub custom_presets: Vec<ProfilingPreset>,
|
pub custom_presets: Vec<ProfilingPreset>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub enable_i1pro2_leds: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for AppSettings {
|
impl Default for AppSettings {
|
||||||
@@ -85,6 +87,7 @@ impl Default for AppSettings {
|
|||||||
delta_e_good_max: default_delta_e_good_max(),
|
delta_e_good_max: default_delta_e_good_max(),
|
||||||
delta_e_warning_max: default_delta_e_warning_max(),
|
delta_e_warning_max: default_delta_e_warning_max(),
|
||||||
custom_presets: Vec::new(),
|
custom_presets: Vec::new(),
|
||||||
|
enable_i1pro2_leds: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -466,4 +469,28 @@ mod tests {
|
|||||||
assert_eq!(parse_log_level_filter(Some("unknown")), log::LevelFilter::Info);
|
assert_eq!(parse_log_level_filter(Some("unknown")), log::LevelFilter::Info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_default_enable_i1pro2_leds() {
|
||||||
|
let settings = AppSettings::default();
|
||||||
|
assert_eq!(settings.enable_i1pro2_leds, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_enable_i1pro2_leds_serialization() {
|
||||||
|
// Missing field defaults to false
|
||||||
|
let json_empty = "{}";
|
||||||
|
let settings_empty: AppSettings = serde_json::from_str(json_empty).unwrap();
|
||||||
|
assert_eq!(settings_empty.enable_i1pro2_leds, false);
|
||||||
|
|
||||||
|
// Explicit true
|
||||||
|
let json_true = r#"{"enable_i1pro2_leds": true}"#;
|
||||||
|
let settings_true: AppSettings = serde_json::from_str(json_true).unwrap();
|
||||||
|
assert_eq!(settings_true.enable_i1pro2_leds, true);
|
||||||
|
|
||||||
|
// Explicit false
|
||||||
|
let json_false = r#"{"enable_i1pro2_leds": false}"#;
|
||||||
|
let settings_false: AppSettings = serde_json::from_str(json_false).unwrap();
|
||||||
|
assert_eq!(settings_false.enable_i1pro2_leds, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "ICCery",
|
"productName": "ICCery",
|
||||||
"version": "0.8.0",
|
"version": "0.8.1",
|
||||||
"identifier": "com.gronod.iccery",
|
"identifier": "com.gronod.iccery",
|
||||||
"build": {
|
"build": {
|
||||||
"frontendDist": "../src"
|
"frontendDist": "../src"
|
||||||
|
|||||||
+14
-4
@@ -883,9 +883,19 @@
|
|||||||
<label for="argyll_binary_dir">ArgyllCMS Binary Directory Override</label>
|
<label for="argyll_binary_dir">ArgyllCMS Binary Directory Override</label>
|
||||||
<input type="text" id="argyll_binary_dir" placeholder="Leave empty for bundled sidecars (e.g. /usr/bin)">
|
<input type="text" id="argyll_binary_dir" placeholder="Leave empty for bundled sidecars (e.g. /usr/bin)">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group" style="margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border-color, #333);">
|
||||||
<label for="default_instrument">Default Instrument Override</label>
|
<label style="font-weight: 600;">Instrument & Measurement Preferences</label>
|
||||||
<input type="text" id="default_instrument" placeholder="e.g. i1">
|
<div style="margin-top: 8px;">
|
||||||
|
<label for="default_instrument" class="sub-label">Default Instrument Override</label>
|
||||||
|
<input type="text" id="default_instrument" placeholder="e.g. i1">
|
||||||
|
</div>
|
||||||
|
<div style="margin-top: 12px;">
|
||||||
|
<label class="checkbox-label" for="enable_i1pro2_leds" style="display: flex; align-items: center; gap: 8px; cursor: pointer;">
|
||||||
|
<input type="checkbox" id="enable_i1pro2_leds">
|
||||||
|
<span>Enable i1Pro 2 status LEDs (<code>-Y l</code>)</span>
|
||||||
|
</label>
|
||||||
|
<small class="help-hint" style="display:block; font-size:0.75rem; color:var(--text-muted, #888); margin-top:3px;">Provides visual status feedback via the instrument ring LEDs during patch reading. Requires patched ArgyllCMS build.</small>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group" style="margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border-color, #333);">
|
<div class="form-group" style="margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border-color, #333);">
|
||||||
<label style="font-weight: 600;">Stage 3 ΔE₀₀ Traffic-Light Thresholds</label>
|
<label style="font-weight: 600;">Stage 3 ΔE₀₀ Traffic-Light Thresholds</label>
|
||||||
@@ -940,7 +950,7 @@
|
|||||||
<img src="./assets/ICCery-logo.svg" alt="ICCery Logo" class="about-logo" />
|
<img src="./assets/ICCery-logo.svg" alt="ICCery Logo" class="about-logo" />
|
||||||
</div>
|
</div>
|
||||||
<h2>About ICCery</h2>
|
<h2>About ICCery</h2>
|
||||||
<p><strong>Version:</strong> <span id="aboutVersion">v0.7.2</span> • <strong>Build Date:</strong> <span id="aboutBuildDate">September 2026</span></p>
|
<p><strong>Version:</strong> <span id="aboutVersion">v0.8.1</span> • <strong>Build Date:</strong> <span id="aboutBuildDate">September 2026</span></p>
|
||||||
<p><strong>Copyright © 2026 Gordon Bolton. All rights reserved.</strong></p>
|
<p><strong>Copyright © 2026 Gordon Bolton. All rights reserved.</strong></p>
|
||||||
<h3>Licences & EULA</h3>
|
<h3>Licences & EULA</h3>
|
||||||
<div class="license-text-container">
|
<div class="license-text-container">
|
||||||
|
|||||||
+7
-2
@@ -426,8 +426,11 @@ export function initChartread() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let lastStderrLine = "";
|
||||||
|
|
||||||
const unlistenStderr = await listen("process:stderr", (event) => {
|
const unlistenStderr = await listen("process:stderr", (event) => {
|
||||||
if (event.payload.id === currentProcessId && event.payload.line) {
|
if (event.payload.id === currentProcessId && event.payload.line) {
|
||||||
|
lastStderrLine = event.payload.line;
|
||||||
logPre.textContent += "ERR: " + event.payload.line + "\n";
|
logPre.textContent += "ERR: " + event.payload.line + "\n";
|
||||||
logPre.scrollTop = logPre.scrollHeight;
|
logPre.scrollTop = logPre.scrollHeight;
|
||||||
}
|
}
|
||||||
@@ -471,8 +474,10 @@ export function initChartread() {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setState(STATE.FINISHED);
|
setState(STATE.FINISHED);
|
||||||
setPrompt(`❌ chartread exited with code ${event.payload.code}.`);
|
if (logContainer) logContainer.open = true;
|
||||||
logPre.textContent += `\n[ERROR] chartread exited with code ${event.payload.code}.\n`;
|
const errDetail = lastStderrLine ? ` (${lastStderrLine})` : "";
|
||||||
|
setPrompt(`❌ chartread exited with code ${event.payload.code}.${errDetail}`);
|
||||||
|
logPre.textContent += `\n[ERROR] chartread exited with code ${event.payload.code}.${errDetail}\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
setMeasurementBusy(false);
|
setMeasurementBusy(false);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export async function initSettings() {
|
|||||||
const deltaEGoodMax = document.getElementById('deltaEGoodMax');
|
const deltaEGoodMax = document.getElementById('deltaEGoodMax');
|
||||||
const deltaEWarningMax = document.getElementById('deltaEWarningMax');
|
const deltaEWarningMax = document.getElementById('deltaEWarningMax');
|
||||||
const deltaEThresholdError = document.getElementById('deltaEThresholdError');
|
const deltaEThresholdError = document.getElementById('deltaEThresholdError');
|
||||||
|
const enableI1Pro2Leds = document.getElementById('enable_i1pro2_leds');
|
||||||
|
|
||||||
if (!dialog || !openBtn) return;
|
if (!dialog || !openBtn) return;
|
||||||
|
|
||||||
@@ -57,6 +58,9 @@ export async function initSettings() {
|
|||||||
const settings = await invoke('load_settings');
|
const settings = await invoke('load_settings');
|
||||||
document.getElementById('argyll_binary_dir').value = settings.argyll_binary_dir || '';
|
document.getElementById('argyll_binary_dir').value = settings.argyll_binary_dir || '';
|
||||||
document.getElementById('default_instrument').value = settings.default_instrument || '';
|
document.getElementById('default_instrument').value = settings.default_instrument || '';
|
||||||
|
if (enableI1Pro2Leds) {
|
||||||
|
enableI1Pro2Leds.checked = Boolean(settings.enable_i1pro2_leds);
|
||||||
|
}
|
||||||
if (logLevelSelect && settings.log_level) {
|
if (logLevelSelect && settings.log_level) {
|
||||||
logLevelSelect.value = settings.log_level;
|
logLevelSelect.value = settings.log_level;
|
||||||
}
|
}
|
||||||
@@ -145,6 +149,7 @@ export async function initSettings() {
|
|||||||
log_level: logLevelSelect ? logLevelSelect.value : (currentSettings.log_level || 'info'),
|
log_level: logLevelSelect ? logLevelSelect.value : (currentSettings.log_level || 'info'),
|
||||||
delta_e_good_max: getInputValueAsFloat('deltaEGoodMax', 2.0),
|
delta_e_good_max: getInputValueAsFloat('deltaEGoodMax', 2.0),
|
||||||
delta_e_warning_max: getInputValueAsFloat('deltaEWarningMax', 5.0),
|
delta_e_warning_max: getInputValueAsFloat('deltaEWarningMax', 5.0),
|
||||||
|
enable_i1pro2_leds: enableI1Pro2Leds ? enableI1Pro2Leds.checked : false,
|
||||||
};
|
};
|
||||||
await invoke('save_settings', { settings });
|
await invoke('save_settings', { settings });
|
||||||
logger.info(`Settings saved. Log level set to: ${settings.log_level}`, 'Settings');
|
logger.info(`Settings saved. Log level set to: ${settings.log_level}`, 'Settings');
|
||||||
|
|||||||
Reference in New Issue
Block a user