AkurAI Build
Menu

cosmic-mobile

public

Latest change 43b1f40498083af2bf229374298cf28e78c02f75 - Add minimal Rust Wayland 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"); }