diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html index d7a1adc..b1f84e4 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html @@ -724,7 +724,7 @@ - +
StartEndBookmarkLabel
StartEndBookmarkLabelInterleave (min)
@@ -741,6 +741,9 @@ + diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/scheduler.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/scheduler.js index bea4949..cebe798 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/scheduler.js +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/scheduler.js @@ -277,11 +277,13 @@ : []; entries.forEach(function (entry, idx) { const tr = document.createElement("tr"); + const il = entry.interleave_min ? String(entry.interleave_min) + " min" : "—"; tr.innerHTML = '' + minToHHMM(entry.start_min) + '' + '' + minToHHMM(entry.end_min) + '' + '' + bmName(entry.bookmark_id) + '' + '' + escHtml(entry.label || "") + '' + + '' + il + '' + ''; tbody.appendChild(tr); }); @@ -330,12 +332,15 @@ const endEl = document.getElementById("scheduler-ts-end"); const bmEl = document.getElementById("scheduler-ts-bookmark"); const labelEl = document.getElementById("scheduler-ts-label"); + const ilEl = document.getElementById("scheduler-ts-entry-interleave"); if (!startEl || !endEl || !bmEl) return; const startMin = hhmmToMin(startEl.value); const endMin = hhmmToMin(endEl.value); const bmId = bmEl.value; const label = labelEl ? labelEl.value.trim() : ""; + const ilVal = ilEl ? parseInt(ilEl.value, 10) : NaN; + const entryInterleave = !isNaN(ilVal) && ilVal > 0 ? ilVal : null; if (!bmId) { alert("Please select a bookmark."); @@ -354,12 +359,14 @@ end_min: endMin, bookmark_id: bmId, label: label || null, + interleave_min: entryInterleave, }); startEl.value = ""; endEl.value = ""; - bmEl.value = ""; // reset select to first option + bmEl.value = ""; if (labelEl) labelEl.value = ""; + if (ilEl) ilEl.value = ""; renderTimespanEntries(); } diff --git a/src/trx-client/trx-frontend/trx-frontend-http/src/scheduler.rs b/src/trx-client/trx-frontend/trx-frontend-http/src/scheduler.rs index a64f6b9..d89790c 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/src/scheduler.rs +++ b/src/trx-client/trx-frontend/trx-frontend-http/src/scheduler.rs @@ -68,6 +68,11 @@ pub struct ScheduleEntry { pub bookmark_id: String, #[serde(default)] pub label: Option, + /// Per-entry interleave duration in minutes. Overrides the config-level + /// `interleave_min` when set. Allows each entry to occupy a differently + /// sized slice of the interleave cycle. + #[serde(default)] + pub interleave_min: Option, } #[derive(Debug, Clone, Serialize, Deserialize, Default)] @@ -284,7 +289,7 @@ fn entry_is_active(entry: &ScheduleEntry, now_min: f64) -> bool { fn timespan_bookmark_id( entries: &[ScheduleEntry], now_min: f64, - interleave_min: Option, + default_interleave: Option, ) -> Option { let active: Vec<&ScheduleEntry> = entries .iter() @@ -295,11 +300,24 @@ fn timespan_bookmark_id( return None; } - // With interleaving and more than one active entry, pick by time slot. + // With interleaving and more than one active entry, use a weighted cycle. + // Each entry's effective duration is its own interleave_min, falling back + // to the config-level default. The cycle length is the sum of all durations. if active.len() > 1 { - if let Some(step) = interleave_min.filter(|&s| s > 0) { - let slot = (now_min as u64 / step as u64) as usize % active.len(); - return Some(active[slot].bookmark_id.clone()); + let durations: Vec = active + .iter() + .map(|e| e.interleave_min.or(default_interleave).unwrap_or(0)) + .collect(); + let cycle: u32 = durations.iter().sum(); + if cycle > 0 { + let pos = (now_min as u64) % (cycle as u64); + let mut cum = 0u64; + for (entry, &dur) in active.iter().zip(durations.iter()) { + cum += dur as u64; + if pos < cum { + return Some(entry.bookmark_id.clone()); + } + } } }