From 9a398d79ff58e55b9e58cc0e9cf288d601ea641f Mon Sep 17 00:00:00 2001 From: MarekSpodBiedry <73122968+MarekSpodBiedry@users.noreply.github.com> Date: Tue, 13 Oct 2026 17:50:51 +0200 Subject: [PATCH] Load older sessions whose track height is the bare Fit string (#447) --- crates/model/src/session.rs | 13 +++++++++ crates/model/src/track.rs | 55 +++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/crates/model/src/session.rs b/crates/model/src/session.rs index 449d82da..b0f74214 100644 --- a/crates/model/src/session.rs +++ b/crates/model/src/session.rs @@ -681,6 +681,19 @@ mod tests { assert_eq!(back, s); } + #[test] + fn session_with_legacy_fit_height_loads() { + let mut s = Session::default(); + let t = s.add_track(TrackKind::Audio, ChannelFormat::Stereo, None); + if let Some(track) = s.track_mut(t) { + track.height = crate::TrackHeight::Large; + } + let text = s.to_json().unwrap().replace("\"height\": \"Large\"", "\"height\": \"Fit\""); + assert!(text.contains("\"height\": \"Fit\"")); + let back = Session::from_json(&text).unwrap(); + assert_eq!(back.track(t).map(|tr| tr.height), Some(crate::TrackHeight::Medium)); + } + #[test] fn video_clip_round_trips_and_old_sessions_load() { let mut s = Session::default(); diff --git a/crates/model/src/track.rs b/crates/model/src/track.rs index 9df78c35..663a6a4b 100644 --- a/crates/model/src/track.rs +++ b/crates/model/src/track.rs @@ -84,6 +84,7 @@ impl TrackKind { /// Track heights (View › Track Height presets). #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, serde::Serialize, serde::Deserialize)] +#[serde(from = "TrackHeightRepr")] pub enum TrackHeight { /// Any height from Micro to Extreme, in points. Custom(u16), @@ -99,6 +100,51 @@ pub enum TrackHeight { Fit(u16), } +/// What a saved track height may look like: the current form, or the bare `"Fit"` string older sessions used. +#[derive(serde::Deserialize)] +#[serde(untagged)] +enum TrackHeightRepr { + Current(TrackHeightCurrent), + LegacyFit(LegacyFit), +} + +#[derive(serde::Deserialize)] +enum LegacyFit { + Fit, +} + +/// Mirror of `TrackHeight` that derives the current serialized form. +#[derive(serde::Deserialize)] +enum TrackHeightCurrent { + Custom(u16), + Micro, + Mini, + Small, + Medium, + Large, + Jumbo, + Extreme, + Fit(u16), +} + +impl From for TrackHeight { + fn from(repr: TrackHeightRepr) -> Self { + match repr { + TrackHeightRepr::Current(TrackHeightCurrent::Custom(p)) => TrackHeight::Custom(p), + TrackHeightRepr::Current(TrackHeightCurrent::Micro) => TrackHeight::Micro, + TrackHeightRepr::Current(TrackHeightCurrent::Mini) => TrackHeight::Mini, + TrackHeightRepr::Current(TrackHeightCurrent::Small) => TrackHeight::Small, + TrackHeightRepr::Current(TrackHeightCurrent::Medium) => TrackHeight::Medium, + TrackHeightRepr::Current(TrackHeightCurrent::Large) => TrackHeight::Large, + TrackHeightRepr::Current(TrackHeightCurrent::Jumbo) => TrackHeight::Jumbo, + TrackHeightRepr::Current(TrackHeightCurrent::Extreme) => TrackHeight::Extreme, + TrackHeightRepr::Current(TrackHeightCurrent::Fit(p)) => TrackHeight::Fit(p), + // Older sessions stored Fit with no size, drawn 88 points tall: the default Medium height. + TrackHeightRepr::LegacyFit(LegacyFit::Fit) => TrackHeight::Medium, + } + } +} + impl TrackHeight { pub const ALL: [TrackHeight; 7] = [ TrackHeight::Micro, @@ -328,6 +374,15 @@ impl Track { mod tests { use super::*; + #[test] + fn legacy_fit_string_loads_as_default_height() { + assert_eq!(serde_json::from_str::("\"Fit\"").unwrap(), TrackHeight::Medium); + assert_eq!(serde_json::from_str::("{\"Fit\":120}").unwrap(), TrackHeight::Fit(120)); + assert_eq!(serde_json::to_string(&TrackHeight::Fit(120)).unwrap(), "{\"Fit\":120}"); + assert_eq!(serde_json::from_str::("\"Large\"").unwrap(), TrackHeight::Large); + assert_eq!(serde_json::from_str::("{\"Custom\":50}").unwrap(), TrackHeight::Custom(50)); + } + #[test] fn new_track_defaults() { let t = Track::new(TrackId(1), "Gtr", TrackKind::Audio, ChannelFormat::Stereo, TRACK_COLORS[0]);