nosignal-shell/modules/nexus/pages/LanguageAndRegion.qml
28allday f21e5b5eaf 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>
2026-06-15 18:02:53 +01:00

205 lines
6.8 KiB
QML

import QtQuick
import QtQuick.Layouts
import Caelestia.Config
import qs.components
import qs.components.controls
import qs.services
import qs.modules.nexus.common
PageBase {
id: root
// Temperature units (index 0 = Celsius, 1 = Fahrenheit — matches Weather.formatTemp)
readonly property list<MenuItem> tempItems: [
MenuItem {
text: "°C"
},
MenuItem {
text: "°F"
}
]
// Clock format (index 0 = 24-hour, 1 = 12-hour — matches Time.useTwelveHourClock)
readonly property list<MenuItem> clockItems: [
MenuItem {
text: qsTr("24-hour")
},
MenuItem {
text: qsTr("12-hour")
}
]
title: qsTr("Language & region")
ColumnLayout {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
width: root.cappedWidth
spacing: Tokens.spacing.extraSmall / 2
// Language
SectionHeader {
first: true
text: qsTr("Language")
}
// Read-only: the shell follows the system locale (no in-shell translations yet)
ConnectedRect {
Layout.fillWidth: true
first: true
last: true
implicitHeight: localeLayout.implicitHeight + localeLayout.anchors.margins * 2
RowLayout {
id: localeLayout
anchors.fill: parent
anchors.margins: Tokens.padding.medium
anchors.leftMargin: Tokens.padding.largeIncreased
anchors.rightMargin: Tokens.padding.largeIncreased
spacing: Tokens.spacing.medium
ColumnLayout {
Layout.fillWidth: true
spacing: 0
StyledText {
Layout.fillWidth: true
text: qsTr("System language")
font: Tokens.font.body.small
elide: Text.ElideRight
}
StyledText {
Layout.fillWidth: true
text: qsTr("Follows your system locale (%1)").arg(Qt.locale().name)
color: Colours.palette.m3outline
font: Tokens.font.label.small
elide: Text.ElideRight
}
}
StyledText {
text: Qt.locale().nativeLanguageName || Qt.locale().name
color: Colours.palette.m3onSurfaceVariant
font: Tokens.font.body.small
}
}
}
// Weather
SectionHeader {
text: qsTr("Weather")
}
// 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: weatherLayout.implicitHeight + weatherLayout.anchors.margins * 2
ColumnLayout {
id: weatherLayout
anchors.fill: parent
anchors.margins: Tokens.padding.medium
anchors.leftMargin: Tokens.padding.largeIncreased
anchors.rightMargin: Tokens.padding.largeIncreased
spacing: Tokens.spacing.small
StyledText {
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
wrapMode: Text.WordWrap
text: qsTr("Leave empty to detect your location automatically.")
color: Colours.palette.m3outline
font: Tokens.font.label.small
}
}
}
// Units
SectionHeader {
text: qsTr("Units")
}
SelectRow {
Layout.fillWidth: true
first: true
label: qsTr("Temperature")
subtext: qsTr("Units for weather temperatures")
menuItems: root.tempItems
active: root.tempItems[GlobalConfig.services.useFahrenheit ? 1 : 0]
onSelected: item => GlobalConfig.services.useFahrenheit = root.tempItems.indexOf(item) === 1
}
SelectRow {
Layout.fillWidth: true
last: true
label: qsTr("System temperatures")
subtext: qsTr("Units for CPU and GPU temperatures")
menuItems: root.tempItems
active: root.tempItems[GlobalConfig.services.useFahrenheitPerformance ? 1 : 0]
onSelected: item => GlobalConfig.services.useFahrenheitPerformance = root.tempItems.indexOf(item) === 1
}
// Time & date
SectionHeader {
text: qsTr("Time & date")
}
SelectRow {
Layout.fillWidth: true
first: true
last: true
label: qsTr("Clock format")
subtext: qsTr("How times are shown across the shell")
menuItems: root.clockItems
active: root.clockItems[GlobalConfig.services.useTwelveHourClock ? 1 : 0]
onSelected: item => GlobalConfig.services.useTwelveHourClock = root.clockItems.indexOf(item) === 1
}
}
}