iris-android-app: Copy report always copies; restore the header's text size

Two of the phone's 2026-09-07 night reports (docs/IRIS_TODO.md):

Copy report used to silently decline ("nothing to copy -- run the
benchmark first") whenever no benchmark had run yet, which read on the
phone as the button being unhittable until Diagnostics was pressed first
-- UI_RULES's "a failure is reported where it happened" failure, since it
declined with no visible effect. It now always copies something: with no
benchmark run yet it copies the diagnostics pane's own text instead (which
needs no prior button press either), with a first line saying so, and in
every case appends the ring's tail (LogRing::tail_text,
COPY_REPORT_TAIL_LINES lines, previous commit) instead of the whole ring,
which was the other half of "causes a lot of lag" pasting it into a
message box. app_log.rs wires iris::diagnostics::trace_enabled into the
ring filter that commit added.

The header's four controls no longer fit one row at HEADER_TEXT = 18, and
a previous agent had shrunk it to 13 to make room -- exactly what
UI_RULES forbids (never shrink text to fit a layout). Restored to 18 and
split bench_controls into two rows instead (run+copy, diagnostics+trace),
doubling the header's own height rather than the outer layout's reserved
space (top_bar already sizes to its own content). Checked on this
checkout's emulator: ui-trace's --field box shows two clean, non-
overlapping rows, and a screenshot shows the restored size reading
clearly; a Copy report tap with nothing run yet now logs "copied to
clipboard" instead of declining.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Fable 5.1 committed 2026-09-07 22:26:27 -04:00
1 parent 7485d78d50
commit b8ea723718
2 files changed
+59 -23

No files matched your search

+7 -1
View File
@@ -27,7 +27,13 @@ pub fn install(max_level: log::LevelFilter) {
.with_max_level(max_level) .with_max_level(max_level)
.with_tag("iris-android-app"), .with_tag("iris-android-app"),
); );
if log_ring::install_process_logger(Box::new(inner), max_level).is_err() { if log_ring::install_process_logger(
Box::new(inner),
max_level,
iris::diagnostics::trace_enabled,
)
.is_err()
{
// Not a panic: a logger already installed means logging works, // Not a panic: a logger already installed means logging works,
// just without the ring, and taking the app down over a // just without the ring, and taking the app down over a
// diagnostic would be worse than the diagnostic being missing. // diagnostic would be worse than the diagnostic being missing.
+52 -22
View File
@@ -468,14 +468,21 @@ const HEADER_SURFACE: UiColor = UiColor::new(28, 28, 34, 255);
/// The size every label in the header row is drawn at. /// The size every label in the header row is drawn at.
/// ///
/// One constant for all four rather than a number per button, because the /// One constant for all four rather than a number per button, because the
/// whole row has to be sized together: it was 18 with three controls, and /// whole row has to be sized together. Adding the trace switch made four
/// adding the trace switch made four labels overlap each other on a /// controls too wide for one row at the size three had used (18), and an
/// 1080px screen. Shrinking *one* label to fit is what the UI rules /// earlier pass shrank this constant to 13 to make them fit -- exactly
/// forbid -- a label a different size from its neighbours for a reason the /// what UI_RULES forbids ("never shrink text to make it fit": a label a
/// reader cannot see; changing the row's own type size is a layout /// different size from its neighbours elsewhere in the app for a reason
/// decision, and all four still match. Whoever adds a fifth control has /// the reader cannot see). The fix is [`bench_controls`]'s two rows
/// one number to reconsider rather than four. /// instead, which leaves room to put this back. Whoever adds a fifth
const HEADER_TEXT: f32 = 13.0; /// control reconsiders the row split, not this number.
const HEADER_TEXT: f32 = 18.0;
/// The height of one row of header controls, in dp. `bench_controls` now
/// stacks two of these, so this is the one number to change if a control's
/// own padding ever changes instead of `dp(56)` and `dp(112)` needing to
/// be kept in sync by hand.
const HEADER_ROW_HEIGHT_DP: f32 = 56.0;
fn bench_controls(rsc: &mut Rsc, top_pad: f32) -> StrongWidget { fn bench_controls(rsc: &mut Rsc, top_pad: f32) -> StrongWidget {
let run_rect = rect(Color::rgb(40, 70, 40)) let run_rect = rect(Color::rgb(40, 70, 40))
@@ -499,8 +506,8 @@ fn bench_controls(rsc: &mut Rsc, top_pad: f32) -> StrongWidget {
let copy_rect = rect(Color::rgb(50, 50, 60)) let copy_rect = rect(Color::rgb(50, 50, 60))
.on( .on(
CursorSense::click(), CursorSense::click(),
|ctx: EventIdCtx<'_, Rsc, _, _>, _rsc: &mut Rsc| { |ctx: EventIdCtx<'_, Rsc, _, _>, rsc: &mut Rsc| {
ctx.state.copy_report(); ctx.state.copy_report(rsc);
}, },
) )
.label("Copy report"); .label("Copy report");
@@ -566,11 +573,19 @@ fn bench_controls(rsc: &mut Rsc, top_pad: f32) -> StrongWidget {
.pad(dp(8)) .pad(dp(8))
.add(rsc); .add(rsc);
let buttons = (run, copy, diagnostics, trace).span(Dir::RIGHT).add(rsc); // Two rows rather than one: four controls at the restored `HEADER_TEXT`
// no longer fit a 1080px-wide row (that was the shrink this replaces --
// see the constant's own doc). Grouped by what they act on: the first
// row starts a benchmark and copies its result; the second is the
// diagnostics pane and the switch that decides what it will contain
// next time.
let row1 = (run, copy).span(Dir::RIGHT).add(rsc);
let row2 = (diagnostics, trace).span(Dir::RIGHT).add(rsc);
let buttons = (row1, row2).span(Dir::DOWN).add(rsc);
(rect(HEADER_SURFACE), buttons) (rect(HEADER_SURFACE), buttons)
.stack() .stack()
.height(dp(56)) .height(dp(2.0 * HEADER_ROW_HEIGHT_DP))
.pad(Padding::top(top_pad)) .pad(Padding::top(top_pad))
.add_strong(rsc) .add_strong(rsc)
.any() .any()
@@ -672,23 +687,38 @@ impl BenchClient {
log::info!("iris keyboard diagnostics:\n{report}"); log::info!("iris keyboard diagnostics:\n{report}");
} }
fn copy_report(&mut self) { /// Always copies something, and never depends on `Diagnostics` or
let Some(report) = self.last_report.clone() else { /// `Run benchmark` having been pressed first (docs/IRIS_TODO.md,
log::info!("iris bench report: nothing to copy -- run the benchmark first"); /// 2026-09-07 night: "the copy report button seemed impossible to hit
return; /// until I hit the diagnostics one" -- it was silently declining
}; /// instead of reporting where it had failed, the UI_RULES failure "a
/// failure is reported where it happened"). With no benchmark run yet,
/// it copies the diagnostics pane's own text instead, with a first
/// line saying so -- `diagnostics_text` needs no prior button press
/// either, so this is never actually empty-handed.
fn copy_report(&mut self, rsc: &mut Rsc) {
let Some(platform) = &self.platform else { let Some(platform) = &self.platform else {
log::info!("iris bench report: no platform handle, can't reach the clipboard"); log::info!("iris bench report: no platform handle, can't reach the clipboard");
return; return;
}; };
// The ring goes on the clipboard, not into the pane: the pane is let report = match self.last_report.clone() {
// on screen and a thousand log lines in it would bury the report Some(report) => report,
// somebody pressed the button for, while the clipboard is going None => format!(
// straight into a message to be read elsewhere. "no benchmark has run yet -- these are the diagnostics instead:\n\n{}",
self.diagnostics_text(rsc)
),
};
// The ring's tail goes on the clipboard, not the full ring, and
// not into the on-screen pane either: the full ring can be over a
// thousand lines with tracing on, and pasting that into a phone's
// message box was Iris's own "causes a lot of lag" report. The
// full ring is still reachable through Dev Updater's Runtime tab
// (`devlog`'s provider reads the same ring) -- this only bounds
// what gets inlined here.
let report = format!( let report = format!(
"{report}\n\n=== app log ({}) ===\n{}", "{report}\n\n=== app log ({}) ===\n{}",
crate::app_log::ring().summary(), crate::app_log::ring().summary(),
crate::app_log::ring().to_text() crate::app_log::ring().tail_text(client_core::log_ring::COPY_REPORT_TAIL_LINES)
); );
if platform.copy_to_clipboard("iris bench report", &report) { if platform.copy_to_clipboard("iris bench report", &report) {
log::info!("iris bench report: copied to clipboard"); log::info!("iris bench report: copied to clipboard");