1use crate::{ActiveTheme, kit};
3use gpui_kit::App;
4use std::sync::LazyLock;
5
6static RADIAL_ARTWORK: LazyLock<String> = LazyLock::new(|| {
7 let mut svg = String::from(
8 r#"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g fill="none" stroke="white" stroke-width="2" stroke-linecap="round">"#,
9 );
10 for ray in 0..12 {
11 svg.push_str(&format!(
12 r#"<path d="M12 3v4" transform="rotate({} 12 12)" opacity="{}"/>"#,
13 ray * 30,
14 0.15 + ray as f32 / 11. * 0.85,
15 ));
16 }
17 svg.push_str("</g></svg>");
18 svg
19});
20
21pub fn native_spinner(cx: &App) -> kit::spinner::Spinner {
25 #[cfg(target_os = "macos")]
26 let artwork = crate::native_symbols::svg_for_path(&crate::IconName::Loader.path());
27 #[cfg(target_os = "macos")]
28 let artwork = artwork
29 .as_deref()
30 .unwrap_or_else(|| RADIAL_ARTWORK.as_bytes());
31 #[cfg(not(target_os = "macos"))]
32 let artwork = RADIAL_ARTWORK.as_bytes();
33 kit::spinner::Spinner::new()
34 .icon(kit::Icon::default().data(artwork))
35 .color(cx.macos().secondary)
36 .ease(|progress| progress)
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42 use gpui_kit::{Context, IntoElement, Render, TestAppContext, Window, px, size};
43
44 struct Indicator;
45 impl Render for Indicator {
46 fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
47 native_spinner(cx)
48 }
49 }
50
51 #[gpui_kit::test]
52 fn radial_indicator_respects_reduce_motion(cx: &mut TestAppContext) {
53 cx.update(|cx| {
54 crate::init(cx);
55 cx.set_reduce_motion(true);
56 });
57 let window = cx.open_window(size(px(80.), px(80.)), |_, _| Indicator);
58 cx.run_until_parked();
59 assert_eq!(
60 window
61 .update(cx, |_, window, cx| window.simulate_next_frame(cx))
62 .unwrap(),
63 0
64 );
65 }
66}