AkurAI Build
Menu

cosmic-mobile

public

Latest change dc9bba1298897771c885931ff76e1a0995d3652b - Fix iOS control details: delete glyph, switches, pill zero, hidden scrollbar, truncated rows by AkurAI Build

//! iOS 26 style upgrades applied to the existing system controls.
use eframe::egui::*;
pub const BLUE: Color32 = Color32::from_rgb(10, 132, 255);
pub const GREEN: Color32 = Color32::from_rgb(48, 209, 88);
pub const RED: Color32 = Color32::from_rgb(255, 69, 58);
pub const ORANGE: Color32 = Color32::from_rgb(255, 159, 10);
pub const BACKGROUND: Color32 = Color32::from_rgb(0, 0, 0);
pub const CARD: Color32 = Color32::from_rgb(28, 28, 30);
pub const FIELD: Color32 = Color32::from_rgb(44, 44, 46);
pub const KEY: Color32 = Color32::from_rgb(51, 51, 51);
pub const KEY_LIGHT: Color32 = Color32::from_rgb(165, 165, 165);
pub const SECONDARY: Color32 = Color32::from_rgb(142, 142, 147);
pub fn back(ui: &mut Ui, label: &str) -> bool {
    ui.add(
        Button::new(RichText::new(format!("‹ {label}")).size(17.).color(BLUE))
            .frame(false)
            .min_size(vec2(88., 44.)),
    )
    .clicked()
}
pub fn large_title(ui: &mut Ui, text: &str) {
    ui.add_space(4.);
    ui.label(RichText::new(text).size(34.).strong());
    ui.add_space(12.);
}
pub fn caption(ui: &mut Ui, text: &str) {
    ui.label(
        RichText::new(text.to_uppercase())
            .size(13.)
            .color(SECONDARY),
    );
    ui.add_space(6.);
}
pub fn card(ui: &mut Ui, add: impl FnOnce(&mut Ui)) {
    Frame::new()
        .fill(CARD)
        .corner_radius(16)
        .inner_margin(Margin::symmetric(16, 4))
        .show(ui, |ui| {
            ui.set_width(ui.available_width());
            add(ui);
        });
    ui.add_space(16.);
}
pub fn row(ui: &mut Ui, title: &str, detail: &str) {
    ui.allocate_ui_with_layout(
        vec2(ui.available_width(), 44.),
        Layout::left_to_right(Align::Center),
        |ui| {
            ui.label(RichText::new(title).size(17.));
            ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
                ui.add(Label::new(RichText::new(detail).size(17.).color(SECONDARY)).truncate());
            });
        },
    );
}
/// Backspace glyph painted with strokes; default fonts lack U+232B.
pub fn delete_key(ui: &mut Ui, size: f32) -> Response {
    let (rect, response) = ui.allocate_exact_size(vec2(size, size), Sense::click());
    response.widget_info(|| WidgetInfo::labeled(WidgetType::Button, true, "Delete"));
    let c = rect.center();
    let s = Stroke::new(2.5_f32, KEY_LIGHT);
    let (w, h) = (size * 0.26, size * 0.17);
    ui.painter().add(Shape::closed_line(
        vec![
            c + vec2(-w, 0.),
            c + vec2(-w * 0.45, -h),
            c + vec2(w, -h),
            c + vec2(w, h),
            c + vec2(-w * 0.45, h),
        ],
        s,
    ));
    let x = size * 0.07;
    ui.painter()
        .line_segment([c + vec2(-x * 0.6, -x), c + vec2(x * 1.6, x)], s);
    ui.painter()
        .line_segment([c + vec2(-x * 0.6, x), c + vec2(x * 1.6, -x)], s);
    response
}
pub fn field(ui: &mut Ui, text: &mut String, hint: &str) -> Response {
    Frame::new()
        .fill(FIELD)
        .corner_radius(12)
        .inner_margin(Margin::symmetric(14, 0))
        .show(ui, |ui| {
            ui.add_sized(
                [ui.available_width(), 48.],
                TextEdit::singleline(text)
                    .hint_text(hint)
                    .font(FontId::proportional(17.))
                    .frame(false),
            )
        })
        .inner
}
pub fn primary(ui: &mut Ui, label: &str, fill: Color32) -> bool {
    ui.add_space(8.);
    let clicked = ui
        .add_sized(
            [ui.available_width(), 50.],
            Button::new(RichText::new(label).size(17.).strong())
                .fill(fill)
                .corner_radius(14),
        )
        .clicked();
    ui.add_space(8.);
    clicked
}
pub fn key(ui: &mut Ui, label: &str, size: f32, fill: Color32, text: Color32) -> Response {
    let (rect, response) = ui.allocate_exact_size(vec2(size, size), Sense::click());
    response.widget_info(|| WidgetInfo::labeled(WidgetType::Button, true, label));
    let fill = if response.is_pointer_button_down_on() {
        fill.gamma_multiply(1.4)
    } else {
        fill
    };
    ui.painter().circle_filled(rect.center(), size / 2., fill);
    ui.painter().text(
        rect.center(),
        Align2::CENTER_CENTER,
        label,
        FontId::proportional(size * 0.42),
        text,
    );
    response
}
pub fn toggle(ui: &mut Ui, on: &mut bool, title: &str) -> Response {
    let mut response = ui
        .allocate_ui_with_layout(
            vec2(ui.available_width(), 44.),
            Layout::left_to_right(Align::Center),
            |ui| {
                ui.label(RichText::new(title).size(17.));
                ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
                    let (rect, r) = ui.allocate_exact_size(vec2(51., 31.), Sense::click());
                    r.widget_info(|| WidgetInfo::selected(WidgetType::Checkbox, true, *on, title));
                    let t = ui.ctx().animate_bool(r.id, *on);
                    let fill = Color32::from_rgb(57, 57, 60).lerp_to_gamma(GREEN, t);
                    ui.painter().rect_filled(rect, 15.5, fill);
                    let x = rect.left() + 15.5 + t * (rect.width() - 31.);
                    ui.painter()
                        .circle_filled(pos2(x, rect.center().y), 13.5, Color32::WHITE);
                    r
                })
                .inner
            },
        )
        .inner;
    if response.clicked() {
        *on = !*on;
        response.mark_changed();
    }
    response
}
pub fn pill(ui: &mut Ui, label: &str, width: f32, height: f32, fill: Color32) -> Response {
    let (rect, response) = ui.allocate_exact_size(vec2(width, height), Sense::click());
    response.widget_info(|| WidgetInfo::labeled(WidgetType::Button, true, label));
    let fill = if response.is_pointer_button_down_on() {
        fill.gamma_multiply(1.4)
    } else {
        fill
    };
    ui.painter().rect_filled(rect, height / 2., fill);
    ui.painter().text(
        pos2(rect.left() + height / 2., rect.center().y),
        Align2::CENTER_CENTER,
        label,
        FontId::proportional(height * 0.42),
        Color32::WHITE,
    );
    response
}