1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-06-15 23:55:21 -04:00
Files
DankMaterialShell/quickshell/Modules/Settings/NetworkWifiTab.qml
T

762 lines
42 KiB
QML

pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import qs.Common
import qs.Modules.Settings.Widgets
import qs.Modals.Common
import qs.Services
import qs.Widgets
Item {
id: networkWifiTab
LayoutMirroring.enabled: I18n.isRtl
LayoutMirroring.childrenInherit: true
Component.onCompleted: {
NetworkService.addRef();
}
Component.onDestruction: {
NetworkService.removeRef();
}
DankFlickable {
anchors.fill: parent
clip: true
contentHeight: mainColumn.height + Theme.spacingXL
contentWidth: width
Column {
id: mainColumn
topPadding: 4
width: Math.min(600, parent.width - Theme.spacingL * 2)
anchors.horizontalCenter: parent.horizontalCenter
spacing: Theme.spacingL
SettingsCard {
id: root
property string expandedWifiSsid: ""
property int maxPinnedWifiNetworks: 3
function normalizePinList(value) {
if (Array.isArray(value))
return value.filter(v => v);
if (typeof value === "string" && value.length > 0)
return [value];
return [];
}
function getPinnedWifiNetworks() {
const pins = SettingsData.wifiNetworkPins || {};
return normalizePinList(pins["preferredWifi"]);
}
function toggleWifiPin(ssid) {
const pins = JSON.parse(JSON.stringify(SettingsData.wifiNetworkPins || {}));
let pinnedList = normalizePinList(pins["preferredWifi"]);
const pinIndex = pinnedList.indexOf(ssid);
if (pinIndex !== -1) {
pinnedList.splice(pinIndex, 1);
} else {
pinnedList.unshift(ssid);
if (pinnedList.length > maxPinnedWifiNetworks)
pinnedList = pinnedList.slice(0, maxPinnedWifiNetworks);
}
if (pinnedList.length > 0)
pins["preferredWifi"] = pinnedList;
else
delete pins["preferredWifi"];
SettingsData.set("wifiNetworkPins", pins);
}
property var forgetNetworkConfirm: ConfirmModal {}
width: parent.width
title: I18n.tr("WiFi")
iconName: "wifi"
settingKey: "networkWifi"
tags: ["wifi", "wi-fi", "wireless", "network", "ssid", "adapter", "radio"]
Column {
id: wifiSection
width: parent.width
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
StyledText {
text: {
if (NetworkService.wifiToggling)
return I18n.tr("Toggling...");
if (!NetworkService.wifiEnabled)
return I18n.tr("Disabled");
if (NetworkService.wifiConnected)
return NetworkService.currentWifiSSID;
return I18n.tr("Not connected");
}
font.pixelSize: Theme.fontSizeSmall
color: NetworkService.wifiConnected ? Theme.primary : Theme.surfaceVariantText
width: parent.width - wifiControls.width - Theme.spacingM
horizontalAlignment: Text.AlignLeft
anchors.verticalCenter: parent.verticalCenter
}
Row {
id: wifiControls
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS
DankActionButton {
iconName: "wifi_find"
buttonSize: 32
visible: NetworkService.backend === "networkmanager" && NetworkService.wifiEnabled && !NetworkService.wifiToggling
onClicked: PopoutService.showHiddenNetworkModal()
}
DankActionButton {
iconName: "refresh"
buttonSize: 32
visible: NetworkService.wifiEnabled && !NetworkService.wifiToggling && !NetworkService.isScanning
onClicked: NetworkService.scanWifi()
}
DankToggle {
checked: NetworkService.wifiEnabled
enabled: !NetworkService.wifiToggling
onToggled: NetworkService.toggleWifiRadio()
}
}
}
Row {
width: parent.width
spacing: Theme.spacingM
visible: NetworkService.wifiEnabled && (NetworkService.wifiDevices?.length ?? 0) > 1
StyledText {
text: I18n.tr("WiFi Device")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: parent.width - wifiDeviceLabel.width - wifiDeviceDropdown.width - Theme.spacingM * 2
height: 1
}
DankDropdown {
id: wifiDeviceDropdown
dropdownWidth: 150
popupWidth: 180
currentValue: NetworkService.wifiDeviceOverride || I18n.tr("Auto")
options: {
const devices = NetworkService.wifiDevices;
if (!devices || devices.length === 0)
return [I18n.tr("Auto")];
return [I18n.tr("Auto")].concat(devices.map(d => d.name));
}
onValueChanged: value => {
const deviceName = value === I18n.tr("Auto") ? "" : value;
NetworkService.setWifiDeviceOverride(deviceName);
}
}
}
StyledText {
id: wifiDeviceLabel
visible: false
text: I18n.tr("WiFi Device")
}
Rectangle {
width: parent.width
height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
visible: NetworkService.wifiEnabled
}
Column {
width: parent.width
spacing: Theme.spacingS
visible: NetworkService.wifiEnabled && !NetworkService.wifiToggling
Column {
width: parent.width
spacing: Theme.spacingS
visible: NetworkService.wifiInterface.length > 0
Row {
width: parent.width
height: 24
StyledText {
text: I18n.tr("Interface:")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
width: 100
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: NetworkService.wifiInterface || "-"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Row {
width: parent.width
height: 24
visible: NetworkService.wifiIP.length > 0
StyledText {
text: I18n.tr("IP Address:")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
width: 100
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: NetworkService.wifiIP || "-"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Row {
width: parent.width
height: 24
visible: NetworkService.wifiConnected
StyledText {
text: I18n.tr("Signal:")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
width: 100
anchors.verticalCenter: parent.verticalCenter
}
Row {
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
DankIcon {
name: {
const s = NetworkService.wifiSignalStrength;
if (s >= 50)
return "wifi";
if (s >= 25)
return "wifi_2_bar";
return "wifi_1_bar";
}
size: 18
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: NetworkService.wifiSignalStrength + "%"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
}
}
}
}
Item {
width: parent.width
height: Theme.spacingS
}
Row {
width: parent.width
spacing: Theme.spacingM
StyledText {
text: I18n.tr("Available Networks")
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: 1
height: 1
Layout.fillWidth: true
}
StyledText {
text: NetworkService.wifiNetworks?.length ?? 0
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter
}
}
Item {
width: parent.width
height: 80
visible: NetworkService.isScanning && (NetworkService.wifiNetworks?.length ?? 0) === 0
Column {
anchors.centerIn: parent
spacing: Theme.spacingS
DankIcon {
id: scanningIcon
name: "wifi_find"
size: 32
color: Theme.surfaceVariantText
anchors.horizontalCenter: parent.horizontalCenter
SequentialAnimation {
running: NetworkService.isScanning
loops: Animation.Infinite
OpacityAnimator {
target: scanningIcon
to: 0.3
duration: 400
easing.type: Easing.InOutQuad
}
OpacityAnimator {
target: scanningIcon
to: 1.0
duration: 400
easing.type: Easing.InOutQuad
}
onRunningChanged: if (!running)
scanningIcon.opacity = 1.0
}
}
StyledText {
text: I18n.tr("Scanning...")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
anchors.horizontalCenter: parent.horizontalCenter
}
}
}
Column {
width: parent.width
spacing: 4
visible: (NetworkService.wifiNetworks?.length ?? 0) > 0
Repeater {
model: {
const ssid = NetworkService.currentWifiSSID;
const networks = NetworkService.wifiNetworks || [];
const pinnedList = root.getPinnedWifiNetworks();
let sorted = [...networks];
sorted.sort((a, b) => {
const aPinnedIndex = pinnedList.indexOf(a.ssid);
const bPinnedIndex = pinnedList.indexOf(b.ssid);
if (aPinnedIndex !== -1 || bPinnedIndex !== -1) {
if (aPinnedIndex === -1)
return 1;
if (bPinnedIndex === -1)
return -1;
return aPinnedIndex - bPinnedIndex;
}
if (a.ssid === ssid)
return -1;
if (b.ssid === ssid)
return 1;
return b.signal - a.signal;
});
return sorted;
}
delegate: Rectangle {
id: wifiNetworkDelegate
required property var modelData
required property int index
readonly property bool isConnected: modelData.ssid === NetworkService.currentWifiSSID
readonly property bool isPinned: root.getPinnedWifiNetworks().includes(modelData.ssid)
readonly property bool isExpanded: root.expandedWifiSsid === modelData.ssid
width: parent.width
height: isExpanded ? 56 + wifiExpandedContent.height : 56
radius: Theme.cornerRadius
color: wifiNetworkMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceLight
border.width: isConnected ? 2 : 0
border.color: Theme.primary
clip: true
Behavior on height {
NumberAnimation {
duration: 150
easing.type: Easing.OutQuad
}
}
Column {
anchors.fill: parent
spacing: 0
Item {
width: parent.width
height: 56
Row {
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
anchors.right: wifiNetworkActions.left
anchors.rightMargin: Theme.spacingS
spacing: Theme.spacingS
DankIcon {
name: {
const s = modelData.signal || 0;
if (s >= 50)
return "wifi";
if (s >= 25)
return "wifi_2_bar";
return "wifi_1_bar";
}
size: 20
color: isConnected ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 2
width: parent.width - 20 - Theme.spacingS
Row {
anchors.left: parent.left
spacing: Theme.spacingXS
StyledText {
text: modelData.ssid || I18n.tr("Unknown")
font.pixelSize: Theme.fontSizeMedium
color: isConnected ? Theme.primary : Theme.surfaceText
font.weight: isConnected ? Font.Medium : Font.Normal
elide: Text.ElideRight
}
DankIcon {
name: "push_pin"
size: 14
color: Theme.primary
visible: isPinned
anchors.verticalCenter: parent.verticalCenter
}
DankIcon {
name: "visibility_off"
size: 14
color: Theme.surfaceVariantText
visible: modelData.hidden || false
anchors.verticalCenter: parent.verticalCenter
}
}
Row {
anchors.left: parent.left
spacing: Theme.spacingXS
StyledText {
text: isConnected ? I18n.tr("Connected") : (modelData.secured ? I18n.tr("Secured") : I18n.tr("Open"))
font.pixelSize: Theme.fontSizeSmall
color: isConnected ? Theme.primary : Theme.surfaceVariantText
}
StyledText {
text: "•"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
visible: modelData.saved
}
StyledText {
text: I18n.tr("Saved")
font.pixelSize: Theme.fontSizeSmall
color: Theme.primary
visible: modelData.saved
}
StyledText {
text: "•"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
visible: modelData.hidden || false
}
StyledText {
text: I18n.tr("Hidden")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
visible: modelData.hidden || false
}
StyledText {
text: "•"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
StyledText {
text: modelData.signal + "%"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
}
}
Row {
id: wifiNetworkActions
anchors.right: parent.right
anchors.rightMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXS
Rectangle {
width: 28
height: 28
radius: 14
color: wifiExpandBtn.containsMouse ? Theme.surfacePressed : "transparent"
visible: isConnected || modelData.saved
DankIcon {
anchors.centerIn: parent
name: isExpanded ? "expand_less" : "expand_more"
size: 18
color: Theme.surfaceText
}
MouseArea {
id: wifiExpandBtn
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (isExpanded) {
root.expandedWifiSsid = "";
} else {
root.expandedWifiSsid = modelData.ssid;
NetworkService.fetchNetworkInfo(modelData.ssid);
}
}
}
}
DankActionButton {
iconName: "qr_code"
buttonSize: 28
visible: modelData.secured && modelData.saved
onClicked: {
PopoutService.showWifiQRCodeModal(modelData.ssid);
}
}
DankActionButton {
iconName: isPinned ? "push_pin" : "push_pin"
buttonSize: 28
iconColor: isPinned ? Theme.primary : Theme.surfaceVariantText
onClicked: {
root.toggleWifiPin(modelData.ssid);
}
}
DankActionButton {
iconName: "delete"
buttonSize: 28
iconColor: Theme.error
visible: modelData.saved || isConnected
onClicked: {
forgetNetworkConfirm.showWithOptions({
title: I18n.tr("Forget Network"),
message: I18n.tr("Forget \"%1\"?").arg(modelData.ssid),
confirmText: I18n.tr("Forget"),
confirmColor: Theme.error,
onConfirm: () => NetworkService.forgetWifiNetwork(modelData.ssid)
});
}
}
}
MouseArea {
id: wifiNetworkMouseArea
anchors.fill: parent
anchors.rightMargin: wifiNetworkActions.width + Theme.spacingM
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (isConnected) {
NetworkService.disconnectWifi();
return;
}
if (modelData.secured && !modelData.saved && (DMSService.apiVersion < 7 || modelData.enterprise)) {
PopoutService.showWifiPasswordModal(modelData.ssid);
return;
}
NetworkService.connectToWifi(modelData.ssid);
}
}
}
Column {
id: wifiExpandedContent
width: parent.width
visible: isExpanded
Rectangle {
width: parent.width - Theme.spacingM * 2
height: 1
x: Theme.spacingM
color: Theme.outlineLight
}
Item {
width: parent.width
height: wifiDetailsColumn.implicitHeight + Theme.spacingM * 2
Column {
id: wifiDetailsColumn
anchors.fill: parent
anchors.margins: Theme.spacingM
spacing: Theme.spacingS
Item {
width: parent.width
height: NetworkService.networkInfoLoading ? 40 : 0
visible: NetworkService.networkInfoLoading
DankSpinner {
anchors.centerIn: parent
size: 20
}
}
Flow {
width: parent.width
spacing: Theme.spacingXS
visible: !NetworkService.networkInfoLoading
Repeater {
model: {
const fields = [];
const net = modelData;
if (!net)
return fields;
fields.push({
label: I18n.tr("Signal"),
value: net.signal + "%"
});
if (net.frequency)
fields.push({
label: I18n.tr("Frequency"),
value: (net.frequency / 1000).toFixed(1) + " GHz"
});
if (net.channel)
fields.push({
label: I18n.tr("Channel"),
value: String(net.channel)
});
if (net.rate)
fields.push({
label: I18n.tr("Rate"),
value: net.rate + " Mbps"
});
if (net.mode)
fields.push({
label: I18n.tr("Mode"),
value: net.mode
});
if (net.bssid)
fields.push({
label: I18n.tr("BSSID"),
value: net.bssid
});
fields.push({
label: I18n.tr("Security"),
value: net.secured ? (net.enterprise ? I18n.tr("Enterprise") : I18n.tr("WPA/WPA2")) : I18n.tr("Open")
});
return fields;
}
delegate: Rectangle {
required property var modelData
required property int index
width: wifiFieldContent.width + Theme.spacingM * 2
height: 32
radius: Theme.cornerRadius - 2
color: Theme.surfaceContainerHigh
border.width: 1
border.color: Theme.outlineLight
Row {
id: wifiFieldContent
anchors.centerIn: parent
spacing: Theme.spacingXS
StyledText {
text: modelData.label + ":"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: modelData.value
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
}
}
}
}
Row {
spacing: Theme.spacingS
visible: (modelData.saved || isConnected) && DMSService.apiVersion > 13
DankToggle {
id: autoconnectToggle
text: I18n.tr("Autoconnect")
checked: modelData.autoconnect || false
onToggled: checked => {
NetworkService.setWifiAutoconnect(modelData.ssid, checked);
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}