From 4efe93cfbfd09a33cdcf649dc3507b0476d6def3 Mon Sep 17 00:00:00 2001 From: MomentDerek <40252940+MomentDerek@users.noreply.github.com> Date: Fri, 23 Jan 2026 23:21:09 +0800 Subject: [PATCH] ui: Fix LoadingLabel animation panic on CJK/emoji text (#45632) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR fixes a crash in LoadingLabel where the loading animation progressively revealed text by slicing with byte offsets (.len()), which can panic for UTF-8 multi-byte characters (e.g., CJK) and emoji. Release Notes: - Fix a crash in LoadingLabel’s loading animation when displaying CJK or emoji text. --- crates/ui/src/components/label/loading_label.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/ui/src/components/label/loading_label.rs b/crates/ui/src/components/label/loading_label.rs index 0b6b027e4775aa960df975c0507e4ac08fbbb545..c3e18fa969f6aedb94985ae5dd99e375d5b45e3d 100644 --- a/crates/ui/src/components/label/loading_label.rs +++ b/crates/ui/src/components/label/loading_label.rs @@ -93,14 +93,15 @@ impl RenderOnce for LoadingLabel { move |mut label, animation_ix, delta| { match animation_ix { 0 => { - let chars_to_show = (delta * text.len() as f32).ceil() as usize; - let text = SharedString::from(text[0..chars_to_show].to_string()); - label.set_text(text); + let byte_end = + text.floor_char_boundary((delta * text.len() as f32).ceil() as usize); + let visible_text = SharedString::new(&text[0..byte_end]); + label.set_text(visible_text); } 1 => match delta { - d if d < 0.25 => label.set_text(text.clone()), - d if d < 0.5 => label.set_text(format!("{}.", text)), - d if d < 0.75 => label.set_text(format!("{}..", text)), + ..0.25 => label.set_text(text.clone()), + ..0.5 => label.set_text(format!("{}.", text)), + ..0.75 => label.set_text(format!("{}..", text)), _ => label.set_text(format!("{}...", text)), }, _ => {}