ui: Fix LoadingLabel animation panic on CJK/emoji text (#45632)

MomentDerek created

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.

Change summary

crates/ui/src/components/label/loading_label.rs | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)

Detailed changes

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)),
                     },
                     _ => {}