chore: fix rest of formatting issues

This commit is contained in:
2 * r + 2 * t 2026-03-22 16:08:57 +11:00
parent f46764fd5d
commit 25515fd32b
24 changed files with 582 additions and 597 deletions

View file

@ -61,13 +61,6 @@ Item {
readOnly: root.readOnly
enabled: root.enabled
Binding {
target: inputField
property: "text"
value: root.text
when: !inputField.activeFocus
}
onTextChanged: {
root.text = text;
root.textEdited(text);
@ -76,6 +69,13 @@ Item {
onEditingFinished: {
root.editingFinished();
}
Binding {
target: inputField
property: "text"
value: root.text
when: !inputField.activeFocus
}
}
}
}

View file

@ -15,21 +15,6 @@ JsonObject {
property UseFuzzy useFuzzy: UseFuzzy {}
property Sizes sizes: Sizes {}
component UseFuzzy: JsonObject {
property bool apps: false
property bool actions: false
property bool schemes: false
property bool variants: false
property bool wallpapers: false
}
component Sizes: JsonObject {
property int itemWidth: 600
property int itemHeight: 57
property int wallpaperWidth: 280
property int wallpaperHeight: 200
}
property list<var> actions: [
{
name: "Calculator",
@ -144,4 +129,19 @@ JsonObject {
dangerous: false
}
]
component UseFuzzy: JsonObject {
property bool apps: false
property bool actions: false
property bool schemes: false
property bool variants: false
property bool wallpapers: false
}
component Sizes: JsonObject {
property int itemWidth: 600
property int itemHeight: 57
property int wallpaperWidth: 280
property int wallpaperHeight: 200
}
}

View file

@ -8,31 +8,6 @@ JsonObject {
property Toasts toasts: Toasts {}
property Vpn vpn: Vpn {}
component Sizes: JsonObject {
property int width: 430
property int toastWidth: 430
}
component Toasts: JsonObject {
property bool configLoaded: true
property bool chargingChanged: true
property bool gameModeChanged: true
property bool dndChanged: true
property bool audioOutputChanged: true
property bool audioInputChanged: true
property bool capsLockChanged: true
property bool numLockChanged: true
property bool kbLayoutChanged: true
property bool kbLimit: true
property bool vpnChanged: true
property bool nowPlaying: false
}
component Vpn: JsonObject {
property bool enabled: false
property list<var> provider: ["netbird"]
}
property list<var> quickToggles: [
{
id: "wifi",
@ -63,4 +38,29 @@ JsonObject {
enabled: false
}
]
component Sizes: JsonObject {
property int width: 430
property int toastWidth: 430
}
component Toasts: JsonObject {
property bool configLoaded: true
property bool chargingChanged: true
property bool gameModeChanged: true
property bool dndChanged: true
property bool audioOutputChanged: true
property bool audioInputChanged: true
property bool capsLockChanged: true
property bool numLockChanged: true
property bool kbLayoutChanged: true
property bool kbLimit: true
property bool vpnChanged: true
property bool nowPlaying: false
}
component Vpn: JsonObject {
property bool enabled: false
property list<var> provider: ["netbird"]
}
}

View file

@ -90,14 +90,14 @@ Item {
}
}
component Pill: QtObject {
property int start
property int end
}
Component {
id: pillComp
Pill {}
}
component Pill: QtObject {
property int start
property int end
}
}

View file

@ -159,6 +159,76 @@ Item {
}
}
Loader {
asynchronous: true
active: Config.bar.workspaces.activeIndicator
anchors.fill: parent
sourceComponent: Item {
StyledClippingRect {
id: indicator
anchors.left: parent.left
anchors.right: parent.right
y: (view.currentItem?.y ?? 0) - view.contentY
implicitHeight: (view.currentItem as SpecialWsDelegate)?.size ?? 0
color: Colours.palette.m3tertiary
radius: Appearance.rounding.full
Colouriser {
source: view
sourceColor: Colours.palette.m3onSurface
colorizationColor: Colours.palette.m3onTertiary
anchors.horizontalCenter: parent.horizontalCenter
x: 0
y: -indicator.y
implicitWidth: view.width
implicitHeight: view.height
}
Behavior on y {
Anim {
easing.bezierCurve: Appearance.anim.curves.emphasized
}
}
Behavior on implicitHeight {
Anim {
easing.bezierCurve: Appearance.anim.curves.emphasized
}
}
}
}
}
MouseArea {
property real startY
anchors.fill: view
drag.target: view.contentItem
drag.axis: Drag.YAxis
drag.maximumY: 0
drag.minimumY: Math.min(0, view.height - view.contentHeight - Appearance.padding.small)
onPressed: event => startY = event.y
onClicked: event => {
if (Math.abs(event.y - startY) > drag.threshold)
return;
const ws = view.itemAt(event.x, event.y) as SpecialWsDelegate;
if (ws?.modelData)
Hypr.dispatch(`togglespecialworkspace ${ws.modelData.name.slice(8)}`);
else
Hypr.dispatch("togglespecialworkspace special");
}
}
component SpecialWsDelegate: ColumnLayout {
id: ws
@ -297,74 +367,4 @@ Item {
}
}
}
Loader {
asynchronous: true
active: Config.bar.workspaces.activeIndicator
anchors.fill: parent
sourceComponent: Item {
StyledClippingRect {
id: indicator
anchors.left: parent.left
anchors.right: parent.right
y: (view.currentItem?.y ?? 0) - view.contentY
implicitHeight: (view.currentItem as SpecialWsDelegate)?.size ?? 0
color: Colours.palette.m3tertiary
radius: Appearance.rounding.full
Colouriser {
source: view
sourceColor: Colours.palette.m3onSurface
colorizationColor: Colours.palette.m3onTertiary
anchors.horizontalCenter: parent.horizontalCenter
x: 0
y: -indicator.y
implicitWidth: view.width
implicitHeight: view.height
}
Behavior on y {
Anim {
easing.bezierCurve: Appearance.anim.curves.emphasized
}
}
Behavior on implicitHeight {
Anim {
easing.bezierCurve: Appearance.anim.curves.emphasized
}
}
}
}
}
MouseArea {
property real startY
anchors.fill: view
drag.target: view.contentItem
drag.axis: Drag.YAxis
drag.maximumY: 0
drag.minimumY: Math.min(0, view.height - view.contentHeight - Appearance.padding.small)
onPressed: event => startY = event.y
onClicked: event => {
if (Math.abs(event.y - startY) > drag.threshold)
return;
const ws = view.itemAt(event.x, event.y) as SpecialWsDelegate;
if (ws?.modelData)
Hypr.dispatch(`togglespecialworkspace ${ws.modelData.name.slice(8)}`);
else
Hypr.dispatch("togglespecialworkspace special");
}
}
}

View file

@ -26,6 +26,12 @@ StackView {
popEnter: NoAnim {}
popExit: NoAnim {}
Component {
id: subMenuComp
SubMenu {}
}
component NoAnim: Transition {
NumberAnimation {
duration: 0
@ -221,10 +227,4 @@ StackView {
}
}
}
Component {
id: subMenuComp
SubMenu {}
}
}

View file

@ -267,6 +267,13 @@ ColumnLayout {
focus: true
activeFocusOnTab: true
Component.onCompleted: {
if (root.shouldBeVisible) {
// Use Timer for actual delay to ensure focus works correctly
passwordFocusTimer.start();
}
}
Keys.onPressed: event => {
// Ensure we have focus when receiving keyboard input
if (!activeFocus) {
@ -318,13 +325,6 @@ ColumnLayout {
}
}
Component.onCompleted: {
if (root.shouldBeVisible) {
// Use Timer for actual delay to ensure focus works correctly
passwordFocusTimer.start();
}
}
StyledRect {
anchors.fill: parent
radius: Appearance.rounding.normal

View file

@ -10,17 +10,11 @@ import qs.config
Item {
id: model
visible: false
ListModel {
id: _visibleModel
}
property alias visibleModel: _visibleModel
property string activeLabel: ""
property int activeIndex: -1
property var _xkbMap: ({})
property bool _notifiedLimit: false
function start() {
_xkbXmlBase.running = true;
@ -127,14 +121,16 @@ Item {
return code.toUpperCase() + " - " + code;
}
visible: false
ListModel {
id: _visibleModel
}
ListModel {
id: _layoutsModel
}
property var _xkbMap: ({})
property bool _notifiedLimit: false
Process {
id: _xkbXmlBase

View file

@ -35,6 +35,7 @@ CollapsibleSection {
radius: Appearance.rounding.normal
border.width: isCurrent ? 1 : 0
border.color: Colours.palette.m3primary
implicitHeight: schemeRow.implicitHeight + Appearance.padding.normal * 2
StateLayer {
function onClicked(): void {
@ -140,8 +141,6 @@ CollapsibleSection {
}
}
}
implicitHeight: schemeRow.implicitHeight + Appearance.padding.normal * 2
}
}
}

View file

@ -32,6 +32,7 @@ CollapsibleSection {
radius: Appearance.rounding.normal
border.width: modelData.variant === Schemes.currentVariant ? 1 : 0
border.color: Colours.palette.m3primary
implicitHeight: variantRow.implicitHeight + Appearance.padding.normal * 2
StateLayer {
function onClicked(): void {
@ -84,8 +85,6 @@ CollapsibleSection {
font.pointSize: Appearance.font.size.large
}
}
implicitHeight: variantRow.implicitHeight + Appearance.padding.normal * 2
}
}
}

View file

@ -55,6 +55,7 @@ CollapsibleSection {
radius: Appearance.rounding.normal
border.width: isCurrent ? 1 : 0
border.color: Colours.palette.m3primary
implicitHeight: fontFamilySansRow.implicitHeight + Appearance.padding.normal * 2
StateLayer {
function onClicked(): void {
@ -93,8 +94,6 @@ CollapsibleSection {
}
}
}
implicitHeight: fontFamilySansRow.implicitHeight + Appearance.padding.normal * 2
}
}
}
@ -137,6 +136,7 @@ CollapsibleSection {
radius: Appearance.rounding.normal
border.width: isCurrent ? 1 : 0
border.color: Colours.palette.m3primary
implicitHeight: fontFamilyMonoRow.implicitHeight + Appearance.padding.normal * 2
StateLayer {
function onClicked(): void {
@ -175,8 +175,6 @@ CollapsibleSection {
}
}
}
implicitHeight: fontFamilyMonoRow.implicitHeight + Appearance.padding.normal * 2
}
}
}
@ -221,6 +219,7 @@ CollapsibleSection {
radius: Appearance.rounding.normal
border.width: isCurrent ? 1 : 0
border.color: Colours.palette.m3primary
implicitHeight: fontFamilyMaterialRow.implicitHeight + Appearance.padding.normal * 2
StateLayer {
function onClicked(): void {
@ -259,8 +258,6 @@ CollapsibleSection {
}
}
}
implicitHeight: fontFamilyMaterialRow.implicitHeight + Appearance.padding.normal * 2
}
}
}

View file

@ -94,6 +94,7 @@ Item {
color: Audio.sink?.id === modelData.id ? Colours.layer(Colours.palette.m3surfaceContainer, 2) : "transparent"
radius: Appearance.rounding.normal
implicitHeight: outputRowLayout.implicitHeight + Appearance.padding.normal * 2
StateLayer {
function onClicked(): void {
@ -126,8 +127,6 @@ Item {
font.weight: Audio.sink?.id === modelData.id ? 500 : 400
}
}
implicitHeight: outputRowLayout.implicitHeight + Appearance.padding.normal * 2
}
}
}
@ -172,6 +171,7 @@ Item {
color: Audio.source?.id === modelData.id ? Colours.layer(Colours.palette.m3surfaceContainer, 2) : "transparent"
radius: Appearance.rounding.normal
implicitHeight: inputRowLayout.implicitHeight + Appearance.padding.normal * 2
StateLayer {
function onClicked(): void {
@ -204,8 +204,6 @@ Item {
font.weight: Audio.source?.id === modelData.id ? 500 : 400
}
}
implicitHeight: inputRowLayout.implicitHeight + Appearance.padding.normal * 2
}
}
}
@ -278,16 +276,6 @@ Item {
text = Math.round(Audio.volume * 100).toString();
}
Connections {
function onVolumeChanged() {
if (!outputVolumeInput.hasFocus) {
outputVolumeInput.text = Math.round(Audio.volume * 100).toString();
}
}
target: Audio
}
onTextEdited: text => {
if (hasFocus) {
const val = parseInt(text);
@ -303,6 +291,16 @@ Item {
text = Math.round(Audio.volume * 100).toString();
}
}
Connections {
function onVolumeChanged() {
if (!outputVolumeInput.hasFocus) {
outputVolumeInput.text = Math.round(Audio.volume * 100).toString();
}
}
target: Audio
}
}
StyledText {
@ -396,16 +394,6 @@ Item {
text = Math.round(Audio.sourceVolume * 100).toString();
}
Connections {
function onSourceVolumeChanged() {
if (!inputVolumeInput.hasFocus) {
inputVolumeInput.text = Math.round(Audio.sourceVolume * 100).toString();
}
}
target: Audio
}
onTextEdited: text => {
if (hasFocus) {
const val = parseInt(text);
@ -421,6 +409,16 @@ Item {
text = Math.round(Audio.sourceVolume * 100).toString();
}
}
Connections {
function onSourceVolumeChanged() {
if (!inputVolumeInput.hasFocus) {
inputVolumeInput.text = Math.round(Audio.sourceVolume * 100).toString();
}
}
target: Audio
}
}
StyledText {
@ -530,16 +528,6 @@ Item {
text = Math.round(Audio.getStreamVolume(modelData) * 100).toString();
}
Connections {
function onAudioChanged() {
if (!streamVolumeInput.hasFocus && modelData?.audio) {
streamVolumeInput.text = Math.round(modelData.audio.volume * 100).toString();
}
}
target: modelData
}
onTextEdited: text => {
if (hasFocus) {
const val = parseInt(text);
@ -555,6 +543,16 @@ Item {
text = Math.round(Audio.getStreamVolume(modelData) * 100).toString();
}
}
Connections {
function onAudioChanged() {
if (!streamVolumeInput.hasFocus && modelData?.audio) {
streamVolumeInput.text = Math.round(modelData.audio.volume * 100).toString();
}
}
target: modelData
}
}
StyledText {

View file

@ -23,6 +23,7 @@ ColumnLayout {
property Component headerComponent: null
property Component titleSuffix: null
property bool showHeader: true
property alias view: view
signal itemSelected(var item)
@ -61,8 +62,6 @@ ColumnLayout {
}
}
property alias view: view
StyledText {
visible: root.description !== ""
Layout.fillWidth: true

View file

@ -152,14 +152,6 @@ ColumnLayout {
to: root.to
stepSize: root.stepSize
// Use Binding to allow slider to move freely during dragging
Binding {
target: slider
property: "value"
value: root.value
when: !slider.pressed
}
onValueChanged: {
// Update input field text in real-time as slider moves during dragging
// Always update when slider value changes (during dragging or external updates)
@ -176,5 +168,13 @@ ColumnLayout {
inputField.text = root.formatValue(newValue);
}
}
// Use Binding to allow slider to move freely during dragging
Binding {
target: slider
property: "value"
value: root.value
when: !slider.pressed
}
}
}

View file

@ -48,6 +48,11 @@ Item {
nextComponent = targetComponent;
}
onPaneChanged: {
nextComponent = getComponentForPane();
paneId = root.paneIdGenerator(pane);
}
Loader {
id: rightLoader
@ -74,11 +79,6 @@ Item {
]
}
}
onPaneChanged: {
nextComponent = getComponentForPane();
paneId = root.paneIdGenerator(pane);
}
}
}
}

View file

@ -154,16 +154,16 @@ GridView {
opacity: 0
Component.onCompleted: {
opacity = 1;
}
Behavior on opacity {
NumberAnimation {
duration: 1000
easing.type: Easing.OutCubic
}
}
Component.onCompleted: {
opacity = 1;
}
}
}
@ -219,16 +219,16 @@ GridView {
opacity: 0
Component.onCompleted: {
opacity = 1;
}
Behavior on opacity {
NumberAnimation {
duration: 1000
easing.type: Easing.OutCubic
}
}
Component.onCompleted: {
opacity = 1;
}
}
}
}

View file

@ -317,6 +317,10 @@ Item {
opacity: 0
Component.onCompleted: {
opacity = 1;
}
Behavior on opacity {
NumberAnimation {
duration: 1000
@ -324,10 +328,6 @@ Item {
}
}
Component.onCompleted: {
opacity = 1;
}
StateLayer {
function onClicked(): void {
root.session.launcher.active = modelData;

View file

@ -98,6 +98,7 @@ ColumnLayout {
required property int index
width: ListView.view ? ListView.view.width : undefined
implicitHeight: rowLayout.implicitHeight + Appearance.padding.normal * 2
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, (root.session && root.session.vpn && root.session.vpn.active === modelData) ? Colours.tPalette.m3surfaceContainer.a : 0)
radius: Appearance.rounding.normal
@ -258,8 +259,6 @@ ColumnLayout {
}
}
}
implicitHeight: rowLayout.implicitHeight + Appearance.padding.normal * 2
}
}
}

View file

@ -82,6 +82,7 @@ ColumnLayout {
required property int index
width: ListView.view ? ListView.view.width : undefined
implicitHeight: 60
color: Colours.tPalette.m3surfaceContainerHigh
radius: Appearance.rounding.normal
@ -147,8 +148,6 @@ ColumnLayout {
}
}
}
implicitHeight: 60
}
}
}

View file

@ -110,6 +110,7 @@ DeviceList {
required property var modelData
width: ListView.view ? ListView.view.width : undefined
implicitHeight: rowLayout.implicitHeight + Appearance.padding.normal * 2
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, root.activeItem === modelData ? Colours.tPalette.m3surfaceContainer.a : 0)
radius: Appearance.rounding.normal
@ -214,8 +215,6 @@ DeviceList {
}
}
}
implicitHeight: rowLayout.implicitHeight + Appearance.padding.normal * 2
}
}

View file

@ -105,6 +105,7 @@ Item {
color: Colours.tPalette.m3surface
opacity: root.session.network.showPasswordDialog && !root.isClosing ? 1 : 0
scale: root.session.network.showPasswordDialog && !root.isClosing ? 1 : 0.7
Keys.onEscapePressed: closeDialog()
Behavior on opacity {
Anim {}
@ -135,8 +136,6 @@ Item {
}
}
Keys.onEscapePressed: closeDialog()
ColumnLayout {
id: content

View file

@ -38,96 +38,6 @@ Singleton {
"Referer": "https://music.163.com/"
})
ListModel {
id: lyricsModel
}
ListModel {
id: fetchedCandidatesModel
}
Timer {
id: seekTimer
interval: 500
onTriggered: root.isManualSeeking = false
}
// If no local lyrics were loaded within the interval, fall back to NetEase
Timer {
id: fallbackTimer
interval: 200
onTriggered: {
if (lyricsModel.count === 0) {
root.backend = "NetEase";
fallbackToOnline();
}
}
}
Timer {
id: loadDebounce
interval: 50
onTriggered: root._doLoadLyrics()
}
FileView {
id: lyricsMapFileView
path: root.lyricsMapFile
printErrors: false
onLoaded: {
try {
root.lyricsMap = JSON.parse(text());
} catch (e) {
root.lyricsMap = {};
}
}
}
FileView {
id: lrcFile
printErrors: false
onLoaded: {
fallbackTimer.stop();
let parsed = Lrc.parseLrc(text());
if (parsed.length > 0) {
root.backend = "Local";
updateModel(parsed);
loading = false;
} else {
root.backend = "NetEase";
fallbackToOnline();
}
}
}
Connections {
function onActiveChanged() {
root.player = Players.active;
loadLyrics();
}
target: Players
}
Connections {
function onMetadataChanged() {
loadLyrics();
}
target: root.player
ignoreUnknownSignals: true
}
Process {
id: saveLyricsMap
command: ["sh", "-c", `mkdir -p "${root.lyricsDir}" && echo '${JSON.stringify(root.lyricsMap)}' > "${root.lyricsMapFile}"`]
}
function getMetadata() {
if (!player || !player.metadata)
return null;
@ -345,4 +255,95 @@ Singleton {
seekTimer.restart();
}
ListModel {
id: lyricsModel
}
ListModel {
id: fetchedCandidatesModel
}
Timer {
id: seekTimer
interval: 500
onTriggered: root.isManualSeeking = false
}
// If no local lyrics were loaded within the interval, fall back to NetEase
Timer {
id: fallbackTimer
interval: 200
onTriggered: {
if (lyricsModel.count === 0) {
root.backend = "NetEase";
fallbackToOnline();
}
}
}
Timer {
id: loadDebounce
interval: 50
onTriggered: root._doLoadLyrics()
}
FileView {
id: lyricsMapFileView
path: root.lyricsMapFile
printErrors: false
onLoaded: {
try {
root.lyricsMap = JSON.parse(text());
} catch (e) {
root.lyricsMap = {};
}
}
}
FileView {
id: lrcFile
printErrors: false
onLoaded: {
fallbackTimer.stop();
let parsed = Lrc.parseLrc(text());
if (parsed.length > 0) {
root.backend = "Local";
updateModel(parsed);
loading = false;
} else {
root.backend = "NetEase";
fallbackToOnline();
}
}
}
Connections {
function onActiveChanged() {
root.player = Players.active;
loadLyrics();
}
target: Players
}
Connections {
function onMetadataChanged() {
loadLyrics();
}
target: root.player
ignoreUnknownSignals: true
}
Process {
id: saveLyricsMap
command: ["sh", "-c", `mkdir -p "${root.lyricsDir}" && echo '${JSON.stringify(root.lyricsMap)}' > "${root.lyricsMapFile}"`]
}
}

View file

@ -313,6 +313,12 @@ Singleton {
}
}
Component {
id: apComp
AccessPoint {}
}
component AccessPoint: QtObject {
required property var lastIpcObject
readonly property string ssid: lastIpcObject.ssid
@ -323,10 +329,4 @@ Singleton {
readonly property string security: lastIpcObject.security
readonly property bool isSecure: security.length > 0
}
Component {
id: apComp
AccessPoint {}
}
}

View file

@ -872,78 +872,222 @@ Singleton {
return false;
}
component CommandProcess: Process {
id: proc
function checkPendingConnection(): void {
if (root.pendingConnection) {
Qt.callLater(() => {
const connected = root.active && root.active.ssid === root.pendingConnection.ssid;
if (connected) {
connectionCheckTimer.stop();
immediateCheckTimer.stop();
immediateCheckTimer.checkCount = 0;
if (root.pendingConnection.callback) {
root.pendingConnection.callback({
success: true,
output: "Connected",
error: "",
exitCode: 0
});
}
root.pendingConnection = null;
} else {
if (!immediateCheckTimer.running) {
immediateCheckTimer.start();
}
}
});
}
}
property var callback: null
property list<string> command: []
property bool callbackCalled: false
property int exitCode: 0
signal processFinished
environment: ({
LANG: "C.UTF-8",
LC_ALL: "C.UTF-8"
})
stdout: StdioCollector {
id: stdoutCollector
function cidrToSubnetMask(cidr: string): string {
const cidrNum = parseInt(cidr, 10);
if (isNaN(cidrNum) || cidrNum < 0 || cidrNum > 32) {
return "";
}
stderr: StdioCollector {
id: stderrCollector
const mask = (0xffffffff << (32 - cidrNum)) >>> 0;
const octet1 = (mask >>> 24) & 0xff;
const octet2 = (mask >>> 16) & 0xff;
const octet3 = (mask >>> 8) & 0xff;
const octet4 = mask & 0xff;
onStreamFinished: {
const error = text.trim();
if (error && error.length > 0) {
const output = (stdoutCollector && stdoutCollector.text) ? stdoutCollector.text : "";
root.handlePasswordRequired(proc, error, output, -1);
return `${octet1}.${octet2}.${octet3}.${octet4}`;
}
function getWirelessDeviceDetails(interfaceName: string, callback: var): void {
if (!interfaceName || interfaceName.length === 0) {
const activeInterface = root.wirelessInterfaces.find(iface => {
return isConnectedState(iface.state);
});
if (activeInterface && activeInterface.device) {
interfaceName = activeInterface.device;
} else {
if (callback)
callback(null);
return;
}
}
executeCommand(["device", "show", interfaceName], result => {
if (!result.success || !result.output) {
root.wirelessDeviceDetails = null;
if (callback)
callback(null);
return;
}
const details = parseDeviceDetails(result.output, false);
root.wirelessDeviceDetails = details;
if (callback)
callback(details);
});
}
function getEthernetDeviceDetails(interfaceName: string, callback: var): void {
if (!interfaceName || interfaceName.length === 0) {
const activeInterface = root.ethernetInterfaces.find(iface => {
return isConnectedState(iface.state);
});
if (activeInterface && activeInterface.device) {
interfaceName = activeInterface.device;
} else {
if (callback)
callback(null);
return;
}
}
executeCommand(["device", "show", interfaceName], result => {
if (!result.success || !result.output) {
root.ethernetDeviceDetails = null;
if (callback)
callback(null);
return;
}
const details = parseDeviceDetails(result.output, true);
root.ethernetDeviceDetails = details;
if (callback)
callback(details);
});
}
function parseDeviceDetails(output: string, isEthernet: bool): var {
const details = {
ipAddress: "",
gateway: "",
dns: [],
subnet: "",
macAddress: "",
speed: ""
};
if (!output || output.length === 0) {
return details;
}
const lines = output.trim().split("\n");
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const parts = line.split(":");
if (parts.length >= 2) {
const key = parts[0].trim();
const value = parts.slice(1).join(":").trim();
if (key.startsWith("IP4.ADDRESS")) {
const ipParts = value.split("/");
details.ipAddress = ipParts[0] || "";
if (ipParts[1]) {
details.subnet = cidrToSubnetMask(ipParts[1]);
} else {
details.subnet = "";
}
} else if (key === "IP4.GATEWAY") {
if (value !== "--") {
details.gateway = value;
}
} else if (key.startsWith("IP4.DNS")) {
if (value !== "--" && value.length > 0) {
details.dns.push(value);
}
} else if (isEthernet && key === "WIRED-PROPERTIES.MAC") {
details.macAddress = value;
} else if (isEthernet && key === "WIRED-PROPERTIES.SPEED") {
details.speed = value;
} else if (!isEthernet && key === "GENERAL.HWADDR") {
details.macAddress = value;
}
}
}
onExited: code => { // qmllint disable signal-handler-parameters
exitCode = code;
return details;
}
Qt.callLater(() => {
if (callbackCalled) {
processFinished();
return;
}
function refreshOnConnectionChange(): void {
getNetworks(networks => {
const newActive = root.active;
if (proc.callback) {
const output = (stdoutCollector && stdoutCollector.text) ? stdoutCollector.text : "";
const error = (stderrCollector && stderrCollector.text) ? stderrCollector.text : "";
const success = exitCode === 0;
const cmdIsConnection = isConnectionCommand(proc.command);
if (root.handlePasswordRequired(proc, error, output, exitCode)) {
processFinished();
return;
if (newActive && newActive.active) {
Qt.callLater(() => {
if (root.wirelessInterfaces.length > 0) {
const activeWireless = root.wirelessInterfaces.find(iface => {
return isConnectedState(iface.state);
});
if (activeWireless && activeWireless.device) {
getWirelessDeviceDetails(activeWireless.device, () => {});
}
}
const needsPassword = cmdIsConnection && root.detectPasswordRequired(error);
if (!success && cmdIsConnection && root.pendingConnection) {
const failedSsid = root.pendingConnection.ssid;
root.connectionFailed(failedSsid);
if (root.ethernetInterfaces.length > 0) {
const activeEthernet = root.ethernetInterfaces.find(iface => {
return isConnectedState(iface.state);
});
if (activeEthernet && activeEthernet.device) {
getEthernetDeviceDetails(activeEthernet.device, () => {});
}
}
}, 500);
} else {
root.wirelessDeviceDetails = null;
root.ethernetDeviceDetails = null;
}
callbackCalled = true;
callback({
success: success,
output: output,
error: error,
exitCode: proc.exitCode,
needsPassword: needsPassword || false
});
processFinished();
} else {
processFinished();
getWirelessInterfaces(() => {});
getEthernetInterfaces(() => {
if (root.activeEthernet && root.activeEthernet.connected) {
Qt.callLater(() => {
getEthernetDeviceDetails(root.activeEthernet.interface, () => {});
}, 500);
}
});
}
});
}
Component.onCompleted: {
getWifiStatus(() => {});
getNetworks(() => {});
loadSavedConnections(() => {});
getEthernetInterfaces(() => {});
Qt.callLater(() => {
if (root.wirelessInterfaces.length > 0) {
const activeWireless = root.wirelessInterfaces.find(iface => {
return isConnectedState(iface.state);
});
if (activeWireless && activeWireless.device) {
getWirelessDeviceDetails(activeWireless.device, () => {});
}
}
if (root.ethernetInterfaces.length > 0) {
const activeEthernet = root.ethernetInterfaces.find(iface => {
return isConnectedState(iface.state);
});
if (activeEthernet && activeEthernet.device) {
getEthernetDeviceDetails(activeEthernet.device, () => {});
}
}
}, 2000);
}
Component {
@ -952,17 +1096,6 @@ Singleton {
CommandProcess {}
}
component AccessPoint: QtObject {
required property var lastIpcObject
readonly property string ssid: lastIpcObject.ssid
readonly property string bssid: lastIpcObject.bssid
readonly property int strength: lastIpcObject.strength
readonly property int frequency: lastIpcObject.frequency
readonly property bool active: lastIpcObject.active
readonly property string security: lastIpcObject.security
readonly property bool isSecure: security.length > 0
}
Component {
id: apComp
@ -1113,157 +1246,6 @@ Singleton {
}
}
function checkPendingConnection(): void {
if (root.pendingConnection) {
Qt.callLater(() => {
const connected = root.active && root.active.ssid === root.pendingConnection.ssid;
if (connected) {
connectionCheckTimer.stop();
immediateCheckTimer.stop();
immediateCheckTimer.checkCount = 0;
if (root.pendingConnection.callback) {
root.pendingConnection.callback({
success: true,
output: "Connected",
error: "",
exitCode: 0
});
}
root.pendingConnection = null;
} else {
if (!immediateCheckTimer.running) {
immediateCheckTimer.start();
}
}
});
}
}
function cidrToSubnetMask(cidr: string): string {
const cidrNum = parseInt(cidr, 10);
if (isNaN(cidrNum) || cidrNum < 0 || cidrNum > 32) {
return "";
}
const mask = (0xffffffff << (32 - cidrNum)) >>> 0;
const octet1 = (mask >>> 24) & 0xff;
const octet2 = (mask >>> 16) & 0xff;
const octet3 = (mask >>> 8) & 0xff;
const octet4 = mask & 0xff;
return `${octet1}.${octet2}.${octet3}.${octet4}`;
}
function getWirelessDeviceDetails(interfaceName: string, callback: var): void {
if (!interfaceName || interfaceName.length === 0) {
const activeInterface = root.wirelessInterfaces.find(iface => {
return isConnectedState(iface.state);
});
if (activeInterface && activeInterface.device) {
interfaceName = activeInterface.device;
} else {
if (callback)
callback(null);
return;
}
}
executeCommand(["device", "show", interfaceName], result => {
if (!result.success || !result.output) {
root.wirelessDeviceDetails = null;
if (callback)
callback(null);
return;
}
const details = parseDeviceDetails(result.output, false);
root.wirelessDeviceDetails = details;
if (callback)
callback(details);
});
}
function getEthernetDeviceDetails(interfaceName: string, callback: var): void {
if (!interfaceName || interfaceName.length === 0) {
const activeInterface = root.ethernetInterfaces.find(iface => {
return isConnectedState(iface.state);
});
if (activeInterface && activeInterface.device) {
interfaceName = activeInterface.device;
} else {
if (callback)
callback(null);
return;
}
}
executeCommand(["device", "show", interfaceName], result => {
if (!result.success || !result.output) {
root.ethernetDeviceDetails = null;
if (callback)
callback(null);
return;
}
const details = parseDeviceDetails(result.output, true);
root.ethernetDeviceDetails = details;
if (callback)
callback(details);
});
}
function parseDeviceDetails(output: string, isEthernet: bool): var {
const details = {
ipAddress: "",
gateway: "",
dns: [],
subnet: "",
macAddress: "",
speed: ""
};
if (!output || output.length === 0) {
return details;
}
const lines = output.trim().split("\n");
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const parts = line.split(":");
if (parts.length >= 2) {
const key = parts[0].trim();
const value = parts.slice(1).join(":").trim();
if (key.startsWith("IP4.ADDRESS")) {
const ipParts = value.split("/");
details.ipAddress = ipParts[0] || "";
if (ipParts[1]) {
details.subnet = cidrToSubnetMask(ipParts[1]);
} else {
details.subnet = "";
}
} else if (key === "IP4.GATEWAY") {
if (value !== "--") {
details.gateway = value;
}
} else if (key.startsWith("IP4.DNS")) {
if (value !== "--" && value.length > 0) {
details.dns.push(value);
}
} else if (isEthernet && key === "WIRED-PROPERTIES.MAC") {
details.macAddress = value;
} else if (isEthernet && key === "WIRED-PROPERTIES.SPEED") {
details.speed = value;
} else if (!isEthernet && key === "GENERAL.HWADDR") {
details.macAddress = value;
}
}
}
return details;
}
Process {
id: rescanProc
@ -1295,70 +1277,88 @@ Singleton {
}
}
function refreshOnConnectionChange(): void {
getNetworks(networks => {
const newActive = root.active;
component CommandProcess: Process {
id: proc
if (newActive && newActive.active) {
Qt.callLater(() => {
if (root.wirelessInterfaces.length > 0) {
const activeWireless = root.wirelessInterfaces.find(iface => {
return isConnectedState(iface.state);
});
if (activeWireless && activeWireless.device) {
getWirelessDeviceDetails(activeWireless.device, () => {});
}
}
property var callback: null
property list<string> command: []
property bool callbackCalled: false
property int exitCode: 0
if (root.ethernetInterfaces.length > 0) {
const activeEthernet = root.ethernetInterfaces.find(iface => {
return isConnectedState(iface.state);
});
if (activeEthernet && activeEthernet.device) {
getEthernetDeviceDetails(activeEthernet.device, () => {});
}
}
}, 500);
} else {
root.wirelessDeviceDetails = null;
root.ethernetDeviceDetails = null;
signal processFinished
environment: ({
LANG: "C.UTF-8",
LC_ALL: "C.UTF-8"
})
stdout: StdioCollector {
id: stdoutCollector
}
stderr: StdioCollector {
id: stderrCollector
onStreamFinished: {
const error = text.trim();
if (error && error.length > 0) {
const output = (stdoutCollector && stdoutCollector.text) ? stdoutCollector.text : "";
root.handlePasswordRequired(proc, error, output, -1);
}
}
}
getWirelessInterfaces(() => {});
getEthernetInterfaces(() => {
if (root.activeEthernet && root.activeEthernet.connected) {
Qt.callLater(() => {
getEthernetDeviceDetails(root.activeEthernet.interface, () => {});
}, 500);
onExited: code => { // qmllint disable signal-handler-parameters
exitCode = code;
Qt.callLater(() => {
if (callbackCalled) {
processFinished();
return;
}
if (proc.callback) {
const output = (stdoutCollector && stdoutCollector.text) ? stdoutCollector.text : "";
const error = (stderrCollector && stderrCollector.text) ? stderrCollector.text : "";
const success = exitCode === 0;
const cmdIsConnection = isConnectionCommand(proc.command);
if (root.handlePasswordRequired(proc, error, output, exitCode)) {
processFinished();
return;
}
const needsPassword = cmdIsConnection && root.detectPasswordRequired(error);
if (!success && cmdIsConnection && root.pendingConnection) {
const failedSsid = root.pendingConnection.ssid;
root.connectionFailed(failedSsid);
}
callbackCalled = true;
callback({
success: success,
output: output,
error: error,
exitCode: proc.exitCode,
needsPassword: needsPassword || false
});
processFinished();
} else {
processFinished();
}
});
});
}
}
Component.onCompleted: {
getWifiStatus(() => {});
getNetworks(() => {});
loadSavedConnections(() => {});
getEthernetInterfaces(() => {});
Qt.callLater(() => {
if (root.wirelessInterfaces.length > 0) {
const activeWireless = root.wirelessInterfaces.find(iface => {
return isConnectedState(iface.state);
});
if (activeWireless && activeWireless.device) {
getWirelessDeviceDetails(activeWireless.device, () => {});
}
}
if (root.ethernetInterfaces.length > 0) {
const activeEthernet = root.ethernetInterfaces.find(iface => {
return isConnectedState(iface.state);
});
if (activeEthernet && activeEthernet.device) {
getEthernetDeviceDetails(activeEthernet.device, () => {});
}
}
}, 2000);
component AccessPoint: QtObject {
required property var lastIpcObject
readonly property string ssid: lastIpcObject.ssid
readonly property string bssid: lastIpcObject.bssid
readonly property int strength: lastIpcObject.strength
readonly property int frequency: lastIpcObject.frequency
readonly property bool active: lastIpcObject.active
readonly property string security: lastIpcObject.security
readonly property bool isSecure: security.length > 0
}
}