AkurAI Build
Menu

cosmic-mobile

public

Latest change d3d7004802d01b8485c3bf66f0ac23532e0e00ce - Lock dependencies and format shell by AkurAI Build

use eframe::{egui, glow::HasContext};
use std::time::{Duration, SystemTime, UNIX_EPOCH};

#[derive(Default, PartialEq, Debug, Clone, Copy)]
enum Page {
    #[default]
    Home,
    Notes,
    System,
}
struct Shell {
    page: Page,
    notes: String,
    renderer: String,
}
fn clock(seconds: u64) -> String {
    format!("{:02}:{:02}", seconds / 3600 % 24, seconds / 60 % 60)
}
impl eframe::App for Shell {
    fn update(&mut self, ctx: &egui::Context, _: &mut eframe::Frame) {
        ctx.request_repaint_after(Duration::from_secs(1));
        if ctx.input(|i| i.key_pressed(egui::Key::Escape)) {
            self.page = Page::Home;
        }
        egui::TopBottomPanel::bottom("navigation")
            .frame(
                egui::Frame::new()
                    .fill(egui::Color32::from_rgb(23, 28, 34))
                    .inner_margin(20),
            )
            .show(ctx, |ui| {
                ui.columns(3, |cols| {
                    for (col, (label, page)) in cols.iter_mut().zip([
                        ("Home", Page::Home),
                        ("Notes", Page::Notes),
                        ("System", Page::System),
                    ]) {
                        if col
                            .add_sized(
                                [col.available_width(), 52.],
                                egui::Button::new(label).selected(self.page == page),
                            )
                            .clicked()
                        {
                            self.page = page;
                        }
                    }
                });
            });
        egui::CentralPanel::default()
            .frame(
                egui::Frame::new()
                    .fill(egui::Color32::from_rgb(23, 28, 34))
                    .inner_margin(28),
            )
            .show(ctx, |ui| {
                ui.label(
                    egui::RichText::new("COSMIC / MOBILE")
                        .size(16.)
                        .color(egui::Color32::from_rgb(156, 207, 218)),
                );
                ui.add_space(10.);
                ui.label("Rust shell · Wayland prototype");
                ui.add_space(48.);
                match self.page {
                    Page::Home => {
                        let now = SystemTime::now()
                            .duration_since(UNIX_EPOCH)
                            .unwrap_or_default()
                            .as_secs();
                        ui.label(egui::RichText::new(clock(now)).size(76.));
                        ui.label("UTC");
                        ui.add_space(48.);
                        ui.heading("Your space.");
                        ui.add_space(12.);
                        ui.label("A small beginning. No desktop clutter.");
                        ui.add_space(32.);
                        if ui
                            .add_sized(
                                [ui.available_width(), 60.],
                                egui::Button::new("Open scratchpad"),
                            )
                            .clicked()
                        {
                            self.page = Page::Notes;
                        }
                        ui.add_space(16.);
                        ui.label("Notes stay in memory for this session.");
                    }
                    Page::Notes => {
                        ui.heading("Scratchpad");
                        ui.add_space(16.);
                        ui.label("Session only — closing the shell clears this text.");
                        ui.add_space(16.);
                        ui.add_sized(
                            [ui.available_width(), 320.],
                            egui::TextEdit::multiline(&mut self.notes)
                                .hint_text("Write something…")
                                .font(egui::TextStyle::Body),
                        );
                    }
                    Page::System => {
                        ui.heading("System");
                        ui.add_space(24.);
                        ui.label("Graphics renderer");
                        ui.label(egui::RichText::new(&self.renderer).size(19.));
                        ui.add_space(24.);
                        ui.label(format!("Architecture: {}", std::env::consts::ARCH));
                        ui.label("Display: Wayland / OpenGL");
                        ui.add_space(24.);
                        ui.label(
                            "VM hardware is virtual. This does not validate OnePlus 13R drivers.",
                        );
                    }
                }
            });
    }
}
fn main() -> eframe::Result {
    if std::env::var_os("WAYLAND_DISPLAY").is_none() {
        eprintln!("Wayland session required");
        std::process::exit(1);
    }
    let options = eframe::NativeOptions {
        renderer: eframe::Renderer::Glow,
        viewport: egui::ViewportBuilder::default()
            .with_inner_size([450., 990.])
            .with_fullscreen(true),
        ..Default::default()
    };
    eframe::run_native(
        "cosmic-mobile",
        options,
        Box::new(|cc| {
            let gl = cc.gl.as_ref().ok_or("OpenGL context missing")?;
            // SAFETY: eframe owns a current GL context during creation.
            let renderer = unsafe { gl.get_parameter_string(eframe::glow::RENDERER) };
            if ["llvmpipe", "softpipe", "swrast", "swiftshader"]
                .iter()
                .any(|s| renderer.to_lowercase().contains(s))
            {
                return Err("Software renderer rejected".into());
            }
            eprintln!("GPU_RENDERER={renderer}");
            cc.egui_ctx.set_pixels_per_point(2.0);
            let mut style = (*cc.egui_ctx.style()).clone();
            style.visuals = egui::Visuals::dark();
            style.visuals.override_text_color = Some(egui::Color32::from_rgb(237, 241, 245));
            style.spacing.item_spacing = egui::vec2(12., 12.);
            style
                .text_styles
                .insert(egui::TextStyle::Body, egui::FontId::proportional(18.));
            style
                .text_styles
                .insert(egui::TextStyle::Button, egui::FontId::proportional(18.));
            cc.egui_ctx.set_style(style);
            Ok(Box::new(Shell {
                page: Page::Home,
                notes: String::new(),
                renderer,
            }))
        }),
    )
}
#[test]
fn clock_wraps_days() {
    assert_eq!(clock(0), "00:00");
    assert_eq!(clock(86399), "23:59");
    assert_eq!(clock(86400), "00:00");
}