// Date & Time. // // These belong to the machine rather than to Panama, so nothing here is stored // in Panama's settings file -- it would be a second answer to a question the // system already answers. Timezone and network time are read from and written // to timedatectl directly; the clock's presentation lives on Appearance, // because that genuinely is a Panama preference. // // Changing the timezone or network time needs privilege. timedatectl asks // polkit, and a canceled dialog surfaces as an error rather than as a value // that appears to have been accepted. import QtQuick import Quickshell import qs.config import qs.services import qs.modules.clipboard SettingsPage { id: root title: "Date & Time" lede: "Timezone and network time, shared with the whole machine." SettingsCard { title: "Clock" TextRow { label: "Current time" detail: DateTime.timezone === "" ? "Reading the system clock" : DateTime.timezone value: Qt.formatDateTime(clock.date, Settings.use24Hour ? "ddd d MMM HH:mm" : "ddd d MMM h:mm AP") } SettingRow { label: "Set automatically" detail: DateTime.ntpEnabled ? (DateTime.ntpSynchronized ? "Synchronized with a time server" : "Waiting to synchronize") : "The clock is set by hand" controlWidth: 48 divider: false SettingsToggle { anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter checked: DateTime.ntpEnabled enabled: !DateTime.busy onToggled: value => DateTime.setNtp(value) } } } SettingsCard { title: "Timezone" PickerRow { id: zonePicker label: "Time zone" detail: DateTime.timezone === "" ? "Reading the system clock" : DateTime.cityOf(DateTime.timezone) + " — " + DateTime.regionOf(DateTime.timezone) value: DateTime.timezone === "" ? "Unknown" : DateTime.cityOf(DateTime.timezone) divider: false SearchField { id: zoneSearch width: parent.width placeholder: "Search timezones" } Repeater { model: root.matchingZones TextRow { required property var modelData required property int index label: DateTime.cityOf(modelData) detail: DateTime.regionOf(modelData) value: modelData === DateTime.timezone ? "Current" : "" controlWidth: 90 divider: index < root.matchingZones.length - 1 activatable: true onActivated: { DateTime.setTimezone(modelData); zonePicker.collapse(); } } } TextRow { visible: root.matchingZones.length === 0 label: "No timezone matches that" detail: "Try a city or a region, such as \"Denver\" or \"Europe\"" divider: false } } } SettingsCard { visible: DateTime.lastError !== "" title: "The system did not accept that" subtitle: DateTime.lastError } // Bounded so a blank search does not try to lay out six hundred rows. The // current zone is always included, so the card never looks empty when the // field is untouched. readonly property var matchingZones: { const needle = zoneSearch.text.trim().toLowerCase(); const all = DateTime.zones; if (needle === "") { // The zone in effect goes first. Listing a region alphabetically // means the current setting is usually off the bottom of the card, // which makes the list look like it does not know what is set. const current = DateTime.timezone; const nearby = all .filter(zone => zone !== current && DateTime.regionOf(zone) === DateTime.regionOf(current)) .slice(0, 11); return current === "" ? nearby : [current].concat(nearby); } return all.filter(zone => zone.toLowerCase().replace(/_/g, " ").indexOf(needle) >= 0).slice(0, 40); } SystemClock { id: clock precision: SystemClock.Minutes } }