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: {
if (root.hasFullscreen)
return;
const visibilities = Visibilities.getForActive();
visibilities.session = !visibilities.session;
// NoSignal: drive the redesigned full-screen Power Menu (NsOverlay),
// not the old caelestia session panel (now dead code).
NsShell.toggle("power", 0);
}
}

View file

@ -92,41 +92,71 @@ PageBase {
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 {
Layout.fillWidth: true
first: true
last: true
implicitHeight: comingSoon.implicitHeight + Tokens.padding.extraLarge * 2
implicitHeight: weatherLayout.implicitHeight + weatherLayout.anchors.margins * 2
ColumnLayout {
id: comingSoon
id: weatherLayout
anchors.centerIn: parent
width: parent.width - Tokens.padding.largeIncreased * 2
spacing: Tokens.padding.extraSmall
NsIcon {
Layout.alignment: Qt.AlignHCenter
icon: "map"
color: Colours.palette.m3outlineVariant
fontStyle: Tokens.font.icon.extraLarge
}
anchors.fill: parent
anchors.margins: Tokens.padding.medium
anchors.leftMargin: Tokens.padding.largeIncreased
anchors.rightMargin: Tokens.padding.largeIncreased
spacing: Tokens.spacing.small
StyledText {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Location picker coming soon")
color: Colours.palette.m3outlineVariant
font: Tokens.font.title.small
Layout.fillWidth: true
text: qsTr("Location")
font: Tokens.font.body.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 {
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
text: qsTr("Choose your weather location on a map in a future update")
color: Colours.palette.m3outlineVariant
font: Tokens.font.body.small
text: qsTr("Leave empty to detect your location automatically.")
color: Colours.palette.m3outline
font: Tokens.font.label.small
}
}
}

View file

@ -2,8 +2,8 @@ pragma Singleton
pragma ComponentBehavior: Bound
// NoSignal icon remap: Material Symbol name -> Nerd Font (JetBrainsMono NF)
// codepoint (Font Awesome range), via String.fromCharCode so the source stays
// pure ASCII. Used by components/NsIcon. Covers bar/panel icons + the dynamic
// codepoint (Font Awesome + MDI ranges), via String.fromCodePoint so the source
// 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
// unmapped is visible (easy to spot + add a mapping).
@ -14,7 +14,9 @@ Singleton {
id: root
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: {
@ -232,7 +234,20 @@ Singleton {
"stop": root.cp(0xf04d),
"thermostat": root.cp(0xf2c9),
"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 {