fix(nosignal): hardware-test feedback — additions icons, power menu, weather picker

From the 2026-06-15 hardware-test feedback (redesign passed end-to-end):

- Glyphs: map the 12 unmapped additions-page icon names (brush, cloud_sync,
  data_object, deployed_code, movie_edit, neurology, psychology, robot_2,
  smart_toy, sports_esports, videocam, vpn_lock) so the nexus Additional
  Software page stops rendering "?" boxes. Verified Nerd Font codepoints.
- Glyphs: cp() now uses String.fromCodePoint, not fromCharCode — the 5 MDI
  glyphs above 0xFFFF were being truncated by the 16-bit fromCharCode.
- Shortcuts: Super+Escape (session) now drives the redesigned full-screen
  Power Menu via NsShell.toggle("power"); old caelestia session panel is
  now dead code.
- nexus LanguageAndRegion: replace the "coming soon" weather placeholder with
  a real location input bound to GlobalConfig.services.weatherLocation (the
  Weather backend already geocodes / IP-auto-detects).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
28allday 2026-06-15 18:02:53 +01:00
parent 83c6b62c13
commit f21e5b5eaf
3 changed files with 73 additions and 27 deletions

View file

@ -54,8 +54,9 @@ Scope {
onPressed: { onPressed: {
if (root.hasFullscreen) if (root.hasFullscreen)
return; return;
const visibilities = Visibilities.getForActive(); // NoSignal: drive the redesigned full-screen Power Menu (NsOverlay),
visibilities.session = !visibilities.session; // not the old caelestia session panel (now dead code).
NsShell.toggle("power", 0);
} }
} }

View file

@ -92,41 +92,71 @@ PageBase {
text: qsTr("Weather") text: qsTr("Weather")
} }
// Placeholder until the map-based location picker lands // Location for the weather service. Weather.qml accepts a city name
// (geocoded) or a "lat,lon" string, and auto-detects via IP when empty.
ConnectedRect { ConnectedRect {
Layout.fillWidth: true Layout.fillWidth: true
first: true first: true
last: true last: true
implicitHeight: comingSoon.implicitHeight + Tokens.padding.extraLarge * 2 implicitHeight: weatherLayout.implicitHeight + weatherLayout.anchors.margins * 2
ColumnLayout { ColumnLayout {
id: comingSoon id: weatherLayout
anchors.centerIn: parent anchors.fill: parent
width: parent.width - Tokens.padding.largeIncreased * 2 anchors.margins: Tokens.padding.medium
spacing: Tokens.padding.extraSmall anchors.leftMargin: Tokens.padding.largeIncreased
anchors.rightMargin: Tokens.padding.largeIncreased
NsIcon { spacing: Tokens.spacing.small
Layout.alignment: Qt.AlignHCenter
icon: "map"
color: Colours.palette.m3outlineVariant
fontStyle: Tokens.font.icon.extraLarge
}
StyledText { StyledText {
Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true
text: qsTr("Location picker coming soon") text: qsTr("Location")
color: Colours.palette.m3outlineVariant font: Tokens.font.body.small
font: Tokens.font.title.small elide: Text.ElideRight
}
StyledRect {
Layout.fillWidth: true
implicitHeight: locField.implicitHeight + Tokens.padding.medium * 2
radius: Tokens.rounding.small
color: Colours.tPalette.m3surfaceContainerLowest
border.color: Colours.palette.m3outlineVariant
Behavior on border.color {
CAnim {}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.IBeamCursor
onClicked: locField.focus = true
}
StyledTextField {
id: locField
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: Tokens.padding.large
anchors.rightMargin: Tokens.padding.large
text: GlobalConfig.services.weatherLocation
placeholderText: qsTr("City name or lat,long — empty = auto (IP)")
placeholderTextColor: Colours.palette.m3onSurfaceVariant
color: Colours.palette.m3onSurface
onEditingFinished: GlobalConfig.services.weatherLocation = text
}
} }
StyledText { StyledText {
Layout.fillWidth: true Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
text: qsTr("Choose your weather location on a map in a future update") text: qsTr("Leave empty to detect your location automatically.")
color: Colours.palette.m3outlineVariant color: Colours.palette.m3outline
font: Tokens.font.body.small font: Tokens.font.label.small
} }
} }
} }

View file

@ -2,8 +2,8 @@ pragma Singleton
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
// NoSignal icon remap: Material Symbol name -> Nerd Font (JetBrainsMono NF) // NoSignal icon remap: Material Symbol name -> Nerd Font (JetBrainsMono NF)
// codepoint (Font Awesome range), via String.fromCharCode so the source stays // codepoint (Font Awesome + MDI ranges), via String.fromCodePoint so the source
// pure ASCII. Used by components/NsIcon. Covers bar/panel icons + the dynamic // stays pure ASCII. Used by components/NsIcon. Covers bar/panel icons + the dynamic
// Icons.getX() returns. get() falls back to a question glyph so anything // Icons.getX() returns. get() falls back to a question glyph so anything
// unmapped is visible (easy to spot + add a mapping). // unmapped is visible (easy to spot + add a mapping).
@ -14,7 +14,9 @@ Singleton {
id: root id: root
function cp(code: int): string { function cp(code: int): string {
return String.fromCharCode(code); // fromCodePoint (not fromCharCode) so astral-plane glyphs (Nerd Font
// MDI range, > 0xFFFF) emit correct surrogate pairs, not truncated.
return String.fromCodePoint(code);
} }
readonly property var map: { readonly property var map: {
@ -232,7 +234,20 @@ Singleton {
"stop": root.cp(0xf04d), "stop": root.cp(0xf04d),
"thermostat": root.cp(0xf2c9), "thermostat": root.cp(0xf2c9),
"water_drop": root.cp(0xf043), "water_drop": root.cp(0xf043),
"wb_twilight": root.cp(0xf185) "wb_twilight": root.cp(0xf185),
// additions-page icons (nexus Additional Software)
"brush": root.cp(0xf1fc), // fa-paintbrush
"cloud_sync": root.cp(0xf063f), // md-cloud_sync
"data_object": root.cp(0xf0169), // md-code_braces
"deployed_code": root.cp(0xf1b2), // fa-cube
"movie_edit": root.cp(0xf008), // fa-film
"neurology": root.cp(0xee9c), // fa-brain
"psychology": root.cp(0xf133c), // md-head_cog
"robot_2": root.cp(0xee0d), // fa-robot
"smart_toy": root.cp(0xf06a9), // md-robot
"sports_esports": root.cp(0xf11b), // fa-gamepad
"videocam": root.cp(0xf03d), // fa-video_camera
"vpn_lock": root.cp(0xf099d) // md-shield_lock
} }
function get(name: string): string { function get(name: string): string {