feat(k-ui): text_input (label above, app owns text via on_change, caret, erase, submit, secret, placeholder); keys Left/Right/Space/Char/Erase; settings app filter; apps 8-page stack (k-ui overflowed 16K), args page -> 0x1000

This commit is contained in:
2026-10-28 13:48:08 +01:00
parent 2b82f052ae
commit e952a149ec
12 changed files with 322 additions and 44 deletions

View File

@@ -14,7 +14,7 @@ extern crate libkos;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use k_ui::{App, ButtonVariant, Element, Spacing, TextColour, TextStyle, button, column, list_item, text, toggle};
use k_ui::{App, ButtonVariant, Element, Spacing, TextColour, TextStyle, button, column, list_item, text, text_input, toggle};
use libkos::apps::Apps;
use libkos::session::Role;
use manifest::{Capabilities, Capability};
@@ -34,11 +34,13 @@ enum Screen {
About,
}
#[derive(Clone, Copy)]
#[derive(Clone)]
enum Event {
Show(Screen),
/// Allow or revoke this capability of the app on screen.
Flip(Capability),
/// What the app list is narrowed to.
Filter(String),
/// Use the display's `n`th theme.
Theme(usize),
SignOut,
@@ -56,6 +58,8 @@ struct Settings {
screen: Screen,
apps: Option<Apps>,
rows: Vec<AppRow>,
/// Only apps whose name or id has this in it are listed.
filter: String,
/// Who is signed in, and how.
who: Option<(String, Role)>,
/// The display's themes, and which is in use.
@@ -81,7 +85,8 @@ impl Settings {
fn reload(&mut self) {
self.rows.clear();
let Some(apps) = &self.apps else { return };
let mut buf = [0u8; LISTING];
// On the heap: an app's stack is a few pages.
let mut buf = alloc::vec![0u8; LISTING];
let Ok(n) = apps.apps(&mut buf) else {
self.trouble = Some("The permission manager did not answer.".to_string());
return;
@@ -141,12 +146,15 @@ impl Settings {
}
fn app_list(&self) -> Element<Event> {
let rows = self.rows.iter().enumerate().map(|(i, r)| {
let wanted = self.filter.to_ascii_lowercase();
let shown = |r: &&AppRow| r.name.to_ascii_lowercase().contains(&wanted) || r.id.contains(&wanted);
let rows = self.rows.iter().enumerate().filter(|(_, r)| shown(r)).map(|(i, r)| {
let allowed = r.granted.intersect(r.requested).iter().count();
let asked = r.requested.iter().count();
list_item(r.name.clone(), Event::Show(Screen::App(i))).subtitle(format!("{} · {} of {} allowed", r.id, allowed, asked))
});
let view = Self::hint(Self::heading("Apps"), "Esc goes back").children(rows);
let find = text_input("Find an app", self.filter.clone(), Event::Filter).placeholder("Name or id");
let view = Self::hint(Self::heading("Apps"), "Esc goes back, Down goes to the list").child(find).children(rows);
self.with_trouble(view).into()
}
@@ -209,7 +217,7 @@ impl App for Settings {
.collect()
});
let theme = window.and_then(libkos::display::theme).map_or(0, |(i, _)| i);
let mut s = Settings { screen: Screen::Home, apps, rows: Vec::new(), who, themes, theme, trouble: None };
let mut s = Settings { screen: Screen::Home, apps, rows: Vec::new(), filter: String::new(), who, themes, theme, trouble: None };
s.reload();
s
}
@@ -219,6 +227,7 @@ impl App for Settings {
Event::Show(screen) => {
self.trouble = None;
if screen == Screen::Apps {
self.filter.clear();
self.reload();
}
self.screen = screen;
@@ -228,6 +237,7 @@ impl App for Settings {
self.flip(i, cap);
}
}
Event::Filter(f) => self.filter = f,
Event::Theme(i) => self.choose_theme(i),
Event::SignOut => {
if let Some(s) = libkos::start::session() {