Ein lebendes Dokument. Hier stehen Kalibrierungen, Rhythmus und Absprachen zur Oberfläche; es wird aktualisiert, sobald etwas entschieden ist.
Material-Symbole aus androidx.compose.material.icons.outlined.* haben eine nominale Größe — ein 24×24-Raster —, doch der gezeichnete Teil unterscheidet sich von Symbol zu Symbol. Gib allen schlicht Modifier.size(24.dp), und die einen wirken groß und schwer (Bolt, Delete), die anderen winzig (Contacts, VpnKey). Sie müssen von Hand kalibriert werden.
new_size = 24 × 52 / measured_px, begrenzt auf [18..28].52 px ist der Referenzglyph Fingerprint; alles wird an ihm als Einheit gemessen.
| Icon | Größe | Why |
|---|---|---|
| Add, Apps, ArrowBack, Close | 28dp | dünne Linien, Glyph von 36–41 px |
| AutoMode, Bolt, DeleteOutline, Edit, List, Photo, QrCode, Tune, DriveFileRenameOutline | 26dp | mittlere Dichte, Glyph von etwa 47 px |
| LocationOn | 24dp | die Kartennadel — nicht anrühren, sie ist Referenz |
| LocationOff | 26dp | die durchgestrichene Nadel — nicht anrühren |
| ContentCopy, MyLocation, PeopleAlt, Wifi, ExpandMore, ExpandLess | 22dp | breit oder hoch und optisch schwer |
| Contacts, VpnKey | 20dp | mit inneren Details überladen |
Wird überall dort verwendet, wo früher Bolt stand — die Schaltfläche „Automatisierung“ auf der Schlüsselkarte, das Abschnittssymbol in den Einstellungen. Größe 26 dp, wie bei Bolt.
IconsDebugSheet.kt — die Zuordnung iconSizeByName. Der Debug-Bildschirm wird geöffnet aus SettingsScreen mit der Schaltfläche „UI-Symbole (Debug)“: oben eine FlowRow kalibrierter Symbole, unten eine Liste von Namen, Größen und Kontexten.
Wir nutzen die Standardrollen von Material 3, bewusst auf vier begrenzt:
| Role | Größe / Zeilenhöhe | Wo verwendet |
|---|---|---|
titleLarge SemiBold | 22sp/28sp | Der Titel des Bottom Sheets („Für den Gast · <Objekt>“) |
titleMedium SemiBold | 16sp/24sp | Regelüberschriften („Geolokalisierung“, „WLAN“, „Intervall“, „Aktivierung“) und FieldSection-Beschriftungen („Koordinaten“, „Radius“, „Modus“, „Gespeicherte Netze“) |
bodyMedium | 14sp/20sp | Beschriftungen von Optionsfeldern, Text in Pillen-Schaltflächen, Segmentnamen |
bodySmall muted | 12sp/16sp | Status und Hinweise („36540 m bis zum Punkt“, „74 m · Maximum, der Gast darf verringern“, Hinweistexte). Farbe: onSurfaceVariant |
Wir arbeiten vereinbarungsgemäß in Vielfachen von 2 / 4 / 8 / 10 / 14 / 16 / 20. Kein Mal üppig, mal karg: gleiche Elemente bekommen gleiche Abstände.
spacedBy(12.dp). Karten stehen 12 dp auseinander.padding(horizontal=20.dp).padding(top=16.dp).verticalArrangement = spacedBy(16.dp) zwischen den großen Blöcken.spacedBy(2.dp). Nur 2 dp zwischen der fetten Beschriftung und dem Status oder Hinweis darunter, damit sie als Paar aus Titel und Bildunterschrift gelesen werden.Spacer(10.dp). Ebenso bei Geo, der WLAN-Verbindung und der WLAN-Liste.Ein Material-3-Schieberegler belegt im Layout wegen der Mindest-Berührfläche rund 48 dp, wovon die sichtbare Spur nur etwa 4 dp in der Mitte ausmacht, mit je rund 22 dp leerer Berührfläche darüber und darunter. Daher:
Modifier.offset(y=-16.dp) an, um den Regler an den Text heranzuziehen.Modifier.sliderTrim() an (ein Helfer in GuestAutomationEditor.kt), der dem Elternelement eine Höhe von 22 dp statt 48 dp meldet. So ergibt der padding(16.dp) denselben Abstand vom Regler zur Unterkante wie bei Karten, die mit einer Pillen-Schaltfläche enden.Jede Regel — Geolokalisierung, WLAN, Zeit, Autorisierung, Bestätigung — und der Aktivierungsblock nehmen eine von drei Stufen an. Der Symbolkreis der Karte erhält die passende Farbe, wenn der Schalter an ist.
| Key | Label | Colour | Description |
|---|---|---|---|
own |
Der Gast entscheidet | #3BA55D (green) | Der Gast wählt die Einstellung selbst |
suggest |
Preset | #E5B409 (yellow) | Der Wert ist gesetzt, und der Gast darf ihn ändern |
force |
Locked | #CC3322 (red) | Der Wert ist gesetzt, und der Gast kann ihn nicht ändern |
Bei ausgeschaltetem Schalter wird der Kreis grau (#9AA0A6), gleich welche Stufe gewählt ist.
Ein einheitlicher 38-dp-Landeplatz in der ganzen App:
CircleShape, der Hintergrund erhält die Stufenfarbe.contentAlignment = Alignment.Center.In Box(Modifier.size(38.dp), contentAlignment=Center) { RadioButton(...) } einwickeln, damit die Mitte des Optionskreises mit der Mitte des farbigen Kreises darüber fluchtet. Ohne Hülle wandert das Optionsfeld waagerecht, weil RadioButton mit eigenen Innenabständen zeichnet.
Zwischen Optionsfeld und seinem Text: Spacer(14.dp). Zwischen Optionszeilen einer Gruppe: Column(spacedBy(4.dp)).
Die Mindest-Berührfläche ist deaktiviert: CompositionLocalProvider(LocalMinimumInteractiveComponentEnforcement provides false) — sonst schwillt jede Optionszeile auf 48 dp an und zerstört den Rhythmus.
Ein Standard-Schalter von Material 3, rechts vom Kartentitel. Er schaltet die ganze Regel ab, die Stufenfarbe wird dann nicht gezeigt — der Kreis wird grau.
Ein eigenes Bedienelement zum Wechseln der Modi innerhalb einer Regel — derzeit nur im WLAN: „Nach einem bestimmten Netz“ / „Nach den Netzen ringsum“. Zwei Elemente in einer Row, jedes mit weight(1f):
colorScheme.surface, RoundedCornerShape(10.dp), Innenabstand 4dp.primaryContainer, RoundedCornerShape(8.dp), Text in SemiBold.Umriss, Symbol und Text, vollständig abgerundet. Für zweitrangige Aktionen — „Aktuelle Position verwenden“, „Netze in der Umgebung erfassen“. Im deaktivierten Zustand fallen Umriss und Text auf alpha=0.4.
Siehe Abschnitt 3 zu offset(y=-16.dp) und sliderTrim(). Vor einem Schieberegler steht stets ein StatusLine mit Statustext (bodySmall, gedämpft) — „74 m · Maximum, der Gast darf verringern“.
Wird durch Tippen auf die Titelzeile der Karte geöffnet — die ganze Row außer dem Schalter. Es erscheint direkt unter der Kopfzeile, über die volle Breite des Karteninhalts. Dafür:
Box mit onGloballyPositioned, und wir messen ihre Breite in dp.DropdownMenuItem mit dem Modifier Modifier.width(anchorWidthDp).Die Menüeinträge atmen, statt flache Zeilen zu sein: links ein Farbmarker, die Bezeichnung fett, darunter die Beschreibung in kleiner, gedämpfter Schrift. Senkrecht richten sie sich an der ersten Zeile aus, der Bezeichnung.
Anders als die gewöhnlichen farbigen Kreise der Regeln pulsiert der Kopfkreis der Aktivierung.
drawBehind + Stroke(width=6dp).LinearEasing. Nicht FastOutSlowInEasing — sonst zeigt der Zyklusneustart einen sichtbaren Ruck.sin(π·p) × 0.6: bei p=0 und p=1 ist Alpha 0, das Maximum liegt in der Mitte. Der Neustart bleibt unsichtbar.Ein einzelner Satz in einer Oberflächenzeile bekommt keinen Punkt. Punkte erscheinen nur bei zwei oder mehr Sätzen, um sie zu trennen. Das gilt für alle Beschreibungen, Hinweise, Status, Tooltips, Überschriften und einzelnen Sätze.
In Schieberegler-Status im gelben Modus (Vorgegeben) nennen wir die Richtung der Freiheit unverblümt:
In Rot (Gesperrt): „74 m · genau“ / „5 von 7 · genau“.
„Der Gast entscheidet / Vorgegeben / Gesperrt“ haben sich eingebürgert; wir ändern sie nicht.
Hat eine Regel einen Aus-Zustand, drücke ihn mit einem Schalter aus, nicht mit einer Optionswahl wie „Nicht erforderlich / Nein / Aus“. Sonst hat der Nutzer zwei Wege, dasselbe abzuschalten, und das verwirrt.
Examples:
Im Block „Koordinaten“ stehen die Symbole zum Kopieren und Löschen rechts auf Höhe beider Zeilen (Beschriftung und Status). Umgesetzt als Row { Column(weight=1f) { label; status }; CopyIcon; DeleteIcon }. Die Symbole werden senkrecht am Paar als Ganzem zentriert.
Der Körper klappt nur auf, wenn:
Animation: expandVertically(tween(220)) + fadeIn(tween(220)) beim Öffnen, shrinkVertically(tween(180)) + fadeOut(tween(120)) beim Schließen.
Beim Empfang eines Gastschlüssels — nur wenn die App im Bild ist und der Schlüssel neu und keine Wiederholung ist. Sonst speichern wir still.
sin(π·p) × 0.6. Jede Vereinfachung verdirbt das Bild.Zuletzt aktualisiert: 18. April 2026 · Dokumentversion 2.07