mirror of
https://github.com/ZSeven-W/openpencil.git
synced 2026-05-31 19:04:29 +07:00
fix(orchestrator): clamp mobile status-bar levels to root width
The mobile status-bar chrome injected by `mobile_status_bar_json` hardcoded levels.x=286 — the right-aligned cellular/wifi/battery group, sized for a 390-wide iPhone reference. When the C2 plan work started honouring explicit prompt sizes via `explicit_mobile_size` (accepts 240..=520 wide), a 320 x 568 iPhone-SE prompt rendered the chrome at x=286..364 — 44 px past the right edge. Take root `width` as an argument and derive levels.x as `width - 78 - 26` (78 = chrome width, 26 = iOS safe-area gutter, matches the existing 390 reference: 390 - 104 = 286). New test exercises 320-wide root to lock in the no-overflow contract.
This commit is contained in:
parent
07277b381d
commit
bb4c62519d
2 changed files with 37 additions and 4 deletions
|
|
@ -84,7 +84,15 @@ fn status_bar_foreground(fill_hex: &str) -> &'static str {
|
|||
}
|
||||
}
|
||||
|
||||
fn mobile_status_bar_json(root_id: &str, fill_hex: &str) -> serde_json::Value {
|
||||
/// Status-bar chrome for a mobile root frame. `width` is the root frame's
|
||||
/// width so the right-aligned levels group (cellular/wifi/battery) clamps
|
||||
/// to the screen edge instead of overflowing on explicit narrow widths
|
||||
/// (e.g. 320 × 568 iPhone SE). Right-edge inset = 26 to match the iOS
|
||||
/// safe-area gutter the 390-wide reference is built against.
|
||||
fn mobile_status_bar_json(root_id: &str, fill_hex: &str, width: f64) -> serde_json::Value {
|
||||
const LEVELS_WIDTH: f64 = 78.0;
|
||||
const LEVELS_RIGHT_INSET: f64 = 26.0;
|
||||
let levels_x = (width - LEVELS_WIDTH - LEVELS_RIGHT_INSET).max(0.0);
|
||||
let fg = status_bar_foreground(fill_hex);
|
||||
let fg_fill = solid_fill_json(fg);
|
||||
let time_label = serde_json::json!({
|
||||
|
|
@ -186,9 +194,9 @@ fn mobile_status_bar_json(root_id: &str, fill_hex: &str) -> serde_json::Value {
|
|||
"type": "frame",
|
||||
"id": format!("{root_id}-status-bar-levels"),
|
||||
"name": "Levels",
|
||||
"x": 286,
|
||||
"x": levels_x,
|
||||
"y": 24,
|
||||
"width": 78,
|
||||
"width": LEVELS_WIDTH,
|
||||
"height": 14,
|
||||
"layout": "none",
|
||||
"children": [cellular, wifi, battery]
|
||||
|
|
@ -224,7 +232,7 @@ fn build_root_frame_node(
|
|||
is_mobile: bool,
|
||||
) -> Result<PenNode, String> {
|
||||
let children = if is_mobile {
|
||||
serde_json::json!([mobile_status_bar_json(id, fill_hex)])
|
||||
serde_json::json!([mobile_status_bar_json(id, fill_hex, width)])
|
||||
} else {
|
||||
serde_json::json!([])
|
||||
};
|
||||
|
|
|
|||
|
|
@ -116,6 +116,31 @@ fn build_scaffold_mobile_status_bar_uses_fixed_icon_positions() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_scaffold_mobile_status_bar_clamps_levels_to_explicit_narrow_width() {
|
||||
// iPhone SE: 320 wide. The pre-fix scaffold hardcoded levels.x=286
|
||||
// which put the right-aligned chrome (cellular/wifi/battery, 78 wide)
|
||||
// at x=286..364 — 44 px off-screen on a 320-wide root.
|
||||
let mut narrow = plan();
|
||||
narrow.root_frame.width = 320.0;
|
||||
let cmds = build_scaffold(&narrow, true).expect("scaffold");
|
||||
match &cmds[0] {
|
||||
EditorCommand::InsertSubtree { nodes, .. } => {
|
||||
let status_json = serde_json::to_value(&nodes[0].children().expect("children")[0])
|
||||
.expect("status json");
|
||||
let levels = &status_json["children"][1];
|
||||
let levels_x = levels["x"].as_f64().expect("levels x");
|
||||
let levels_w = levels["width"].as_f64().expect("levels width");
|
||||
assert!(
|
||||
levels_x + levels_w <= 320.0,
|
||||
"levels right edge {} overflows root width 320",
|
||||
levels_x + levels_w
|
||||
);
|
||||
}
|
||||
other => panic!("expected InsertSubtree, got {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_scaffold_single_root_uses_safe_canvas_offset() {
|
||||
let cmds = build_scaffold(&plan(), true).expect("scaffold");
|
||||
|
|
|
|||
Loading…
Reference in a new issue