mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-21 18:54:01 -04:00
683 lines
29 KiB
QML
683 lines
29 KiB
QML
pragma ComponentBehavior: Bound
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import qs.Common
|
|
import qs.Modals
|
|
import qs.Modals.Common
|
|
import qs.Modules.ControlCenter
|
|
import qs.Modules.ControlCenter.Widgets
|
|
import qs.Modules.Network
|
|
import qs.Services
|
|
import qs.DCommon.Widgets
|
|
import qs.Widgets
|
|
import "../../../Common/QmlUtils.js" as QmlUtils
|
|
|
|
Item {
|
|
id: root
|
|
|
|
implicitHeight: pageList.contentHeight
|
|
|
|
LayoutMirroring.enabled: I18n.isRtl
|
|
LayoutMirroring.childrenInherit: true
|
|
|
|
property var transientSurfaceTracker: null
|
|
|
|
readonly property string title: I18n.tr("Network")
|
|
|
|
property bool transitioning: false
|
|
property bool holdsScanRef: false
|
|
|
|
Component.onCompleted: acquireScanRef()
|
|
Component.onDestruction: {
|
|
if (holdsScanRef)
|
|
NetworkService.removeRef();
|
|
}
|
|
onTransitioningChanged: acquireScanRef()
|
|
|
|
readonly property bool hasEthernetAvailable: (NetworkService.ethernetDevices?.length ?? 0) > 0
|
|
readonly property bool hasWifiAvailable: (NetworkService.wifiDevices?.length ?? 0) > 0
|
|
readonly property bool hasCellularAvailable: (NetworkService.cellularDevices?.length ?? 0) > 0
|
|
readonly property var connectionTypes: {
|
|
const types = [];
|
|
if (hasEthernetAvailable)
|
|
types.push("ethernet");
|
|
if (hasWifiAvailable)
|
|
types.push("wifi");
|
|
if (hasCellularAvailable)
|
|
types.push("cellular");
|
|
return types.length > 0 ? types : ["wifi"];
|
|
}
|
|
property string selectedType: ""
|
|
readonly property string currentConnectionType: {
|
|
if (selectedType && connectionTypes.includes(selectedType))
|
|
return selectedType;
|
|
return connectionTypes[defaultTypeIndex] || "wifi";
|
|
}
|
|
readonly property bool wifiMode: currentConnectionType === "wifi"
|
|
readonly property bool ethernetMode: currentConnectionType === "ethernet"
|
|
readonly property bool cellularMode: currentConnectionType === "cellular"
|
|
readonly property bool networkManager: NetworkService.backend === "networkmanager"
|
|
// hosting on the sole wifi radio with no ethernet uplink drops connectivity
|
|
readonly property bool hotspotRelevant: NetworkService.hotspotEnabled || NetworkService.hotspotActivating || NetworkService.hotspotBusy || NetworkService.ethernetConnected || (NetworkService.wifiDevices?.length ?? 0) > 1
|
|
readonly property bool showHotspotRow: wifiMode && NetworkService.hotspotAvailable && NetworkService.hotspotConfigured && hotspotRelevant
|
|
readonly property bool hotspotWorking: NetworkService.hotspotBusy || NetworkService.hotspotActivating
|
|
readonly property var pinnedNetworks: QmlUtils.normalizePinList((CacheData.wifiNetworkPins || {})["preferredWifi"])
|
|
readonly property bool wifiScanningEmpty: wifiMode && NetworkService.wifiEnabled && !NetworkService.wifiToggling && NetworkService.wifiInterface && (NetworkService.wifiNetworks?.length ?? 0) < 1 && (NetworkService.isScanning || transitioning)
|
|
readonly property bool wifiListVisible: wifiMode && NetworkService.wifiEnabled && !NetworkService.wifiToggling && !wifiScanningEmpty
|
|
|
|
readonly property bool paneSwitchSupported: connectionTypes.length > 1 && networkManager && DMSService.apiVersion > 10
|
|
readonly property var typeLabels: ({
|
|
"ethernet": I18n.tr("Ethernet"),
|
|
"wifi": I18n.tr("Wi-Fi", "wireless network, page and section title"),
|
|
"cellular": I18n.tr("Cellular")
|
|
})
|
|
readonly property int defaultTypeIndex: {
|
|
const wifiIndex = Math.max(0, connectionTypes.indexOf("wifi"));
|
|
if (!paneSwitchSupported)
|
|
return wifiIndex;
|
|
const byStatus = connectionTypes.indexOf(NetworkService.networkStatus);
|
|
if (byStatus !== -1)
|
|
return byStatus;
|
|
const byPreference = connectionTypes.indexOf(NetworkService.userPreference);
|
|
return byPreference !== -1 ? byPreference : wifiIndex;
|
|
}
|
|
|
|
readonly property Item headerActions: Row {
|
|
spacing: Theme.spacingS
|
|
|
|
DDropdown {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
visible: root.wifiMode && (NetworkService.wifiDevices?.length ?? 0) > 1
|
|
compactMode: true
|
|
dropdownWidth: CcMetrics.headerDropdownWidth
|
|
popupWidth: CcMetrics.headerPopupWidth
|
|
alignPopupRight: true
|
|
options: [I18n.tr("Auto")].concat((NetworkService.wifiDevices || []).map(d => d.name))
|
|
currentValue: NetworkService.wifiDeviceOverride || I18n.tr("Auto")
|
|
onValueChanged: value => NetworkService.setWifiDeviceOverride(value === I18n.tr("Auto") ? "" : value)
|
|
}
|
|
|
|
DRefreshButton {
|
|
Accessible.name: I18n.tr("Scan")
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
buttonSize: CcMetrics.headerActionSize
|
|
iconSize: CcMetrics.headerActionIconSize
|
|
iconColor: Theme.surfaceText
|
|
visible: root.wifiMode && NetworkService.wifiEnabled && !NetworkService.wifiToggling
|
|
busy: NetworkService.isScanning
|
|
onClicked: NetworkService.scanWifi()
|
|
}
|
|
|
|
CcSettingsButton {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
settingsTab: "network_" + root.currentConnectionType
|
|
}
|
|
}
|
|
|
|
function acquireScanRef() {
|
|
if (transitioning || holdsScanRef)
|
|
return;
|
|
holdsScanRef = true;
|
|
NetworkService.addRef();
|
|
}
|
|
|
|
function dismissTransient() {
|
|
if (wifiMenu.open) {
|
|
wifiMenu.close();
|
|
return true;
|
|
}
|
|
if (wiredMenu.open) {
|
|
wiredMenu.close();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function explainHotspotNeedsWiFi() {
|
|
ToastService.showError(I18n.tr("Wi-Fi is disabled", "hotspot start error title"), I18n.tr("Enable Wi-Fi before starting the hotspot.", "hotspot WiFi requirement message"));
|
|
}
|
|
|
|
function startHotspotWithConfirm() {
|
|
if (!NetworkService.hotspotWouldDisconnectWifi) {
|
|
NetworkService.startHotspot();
|
|
return;
|
|
}
|
|
hotspotConfirmLoader.active = true;
|
|
const confirm = hotspotConfirmLoader.item;
|
|
if (!confirm)
|
|
return;
|
|
confirm.showWithOptions({
|
|
title: I18n.tr("Start Hotspot?", "hotspot start confirmation title"),
|
|
message: I18n.tr("Starting the hotspot disconnects Wi-Fi from \"%1\". The radio can\'t do both at once, so sharing internet needs another connection such as Ethernet.", "hotspot WiFi disconnection warning, %1 is the network name").arg(NetworkService.currentWifiSSID),
|
|
confirmText: I18n.tr("Start", "hotspot start confirmation action"),
|
|
onConfirm: () => NetworkService.startHotspot()
|
|
});
|
|
}
|
|
|
|
function togglePin(ssid) {
|
|
CacheData.set("wifiNetworkPins", QmlUtils.togglePinEntry(CacheData.wifiNetworkPins, "preferredWifi", ssid, CcMetrics.maxPins));
|
|
}
|
|
|
|
function openWifiMenu(network, connected, connecting, anchor) {
|
|
const ssid = network.ssid;
|
|
const saved = network.saved || false;
|
|
const showSavedOptions = saved || connected;
|
|
wifiMenu.items = [
|
|
{
|
|
"label": connecting ? I18n.tr("Connecting...") : (connected ? I18n.tr("Disconnect") : I18n.tr("Connect")),
|
|
"iconName": connected ? "wifi_off" : "wifi",
|
|
"enabled": !connecting,
|
|
"action": () => WifiConnectionActions.connectToNetworkFromDetails(ssid, network.secured, saved, network.enterprise, connected, {
|
|
disconnectWhenConnected: true
|
|
})
|
|
},
|
|
{
|
|
"label": I18n.tr("Network Info"),
|
|
"iconName": "info",
|
|
"action": () => {
|
|
networkInfoModalLoader.active = true;
|
|
networkInfoModalLoader.item.showNetworkInfo(ssid, NetworkService.getNetworkInfo(ssid));
|
|
}
|
|
},
|
|
{
|
|
"label": network.autoconnect ? I18n.tr("Disable autoconnect") : I18n.tr("Enable autoconnect"),
|
|
"iconName": "autorenew",
|
|
"visible": showSavedOptions && DMSService.apiVersion > 13,
|
|
"action": () => NetworkService.setWifiAutoconnect(ssid, !network.autoconnect)
|
|
},
|
|
{
|
|
"label": I18n.tr("Forget network"),
|
|
"iconName": "delete",
|
|
"destructive": true,
|
|
"visible": showSavedOptions,
|
|
"action": () => NetworkService.forgetWifiNetwork(ssid)
|
|
}
|
|
];
|
|
wifiMenu.openAt(anchor);
|
|
}
|
|
|
|
function openWiredMenu(connection, anchor) {
|
|
const connected = connection.isActive;
|
|
wiredMenu.items = [
|
|
{
|
|
"label": I18n.tr("Activate"),
|
|
"iconName": "lan",
|
|
"visible": !connected,
|
|
"action": () => NetworkService.connectToSpecificWiredConfig(connection.uuid)
|
|
},
|
|
{
|
|
"label": I18n.tr("Disconnect"),
|
|
"iconName": "link_off",
|
|
"destructive": true,
|
|
"visible": connected,
|
|
"action": () => NetworkService.toggleNetworkConnection("ethernet")
|
|
},
|
|
{
|
|
"label": I18n.tr("Network Info"),
|
|
"iconName": "info",
|
|
"visible": connected,
|
|
"action": () => {
|
|
networkWiredInfoModalLoader.active = true;
|
|
networkWiredInfoModalLoader.item.showNetworkInfo(connection.id, NetworkService.getWiredNetworkInfo(connection.uuid));
|
|
}
|
|
}
|
|
];
|
|
wiredMenu.openAt(anchor);
|
|
}
|
|
|
|
ScriptModel {
|
|
id: wifiListModel
|
|
objectProp: "ssid"
|
|
|
|
readonly property bool frozen: wifiMenu.open || root.transitioning
|
|
property var frozenNetworks: []
|
|
readonly property var sortedNetworks: {
|
|
const ssid = NetworkService.currentWifiSSID;
|
|
const pinnedList = root.pinnedNetworks;
|
|
const sorted = [...(NetworkService.wifiNetworks || [])];
|
|
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;
|
|
const aKnown = !!a.saved && (a.signal || 0) > 0;
|
|
const bKnown = !!b.saved && (b.signal || 0) > 0;
|
|
if (aKnown !== bKnown)
|
|
return aKnown ? -1 : 1;
|
|
const aBucket = Math.floor((a.signal || 0) / CcMetrics.wifiSignalBucket);
|
|
const bBucket = Math.floor((b.signal || 0) / CcMetrics.wifiSignalBucket);
|
|
if (aBucket !== bBucket)
|
|
return bBucket - aBucket;
|
|
return (a.ssid || "").localeCompare(b.ssid || "");
|
|
});
|
|
return sorted;
|
|
}
|
|
|
|
values: frozen ? frozenNetworks : sortedNetworks
|
|
|
|
onSortedNetworksChanged: {
|
|
if (!frozen)
|
|
frozenNetworks = sortedNetworks;
|
|
}
|
|
onFrozenChanged: {
|
|
if (frozen)
|
|
frozenNetworks = sortedNetworks;
|
|
}
|
|
}
|
|
|
|
ScriptModel {
|
|
id: wiredConnectionsModel
|
|
objectProp: "uuid"
|
|
values: {
|
|
const sorted = [...(NetworkService.wiredConnections || [])];
|
|
sorted.sort((a, b) => {
|
|
if (a.isActive !== b.isActive)
|
|
return a.isActive ? -1 : 1;
|
|
return a.id.localeCompare(b.id);
|
|
});
|
|
return sorted;
|
|
}
|
|
}
|
|
|
|
ScriptModel {
|
|
id: cellularConnectionsModel
|
|
objectProp: "uuid"
|
|
values: {
|
|
const sorted = [...(NetworkService.cellularConnections || [])];
|
|
sorted.sort((a, b) => {
|
|
if (a.isActive !== b.isActive)
|
|
return a.isActive ? -1 : 1;
|
|
return (a.id || "").localeCompare(b.id || "");
|
|
});
|
|
return sorted;
|
|
}
|
|
}
|
|
|
|
DListView {
|
|
id: pageList
|
|
objectName: "networkList"
|
|
|
|
anchors.fill: parent
|
|
clip: true
|
|
spacing: Theme.groupedListGap
|
|
add: null
|
|
displaced: null
|
|
move: null
|
|
model: root.wifiListVisible ? wifiListModel : null
|
|
|
|
header: Column {
|
|
width: pageList.width
|
|
spacing: CcMetrics.detailContentGap
|
|
bottomPadding: pageList.count > 0 ? CcMetrics.detailContentGap : 0
|
|
|
|
DButtonGroup {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
size: "small"
|
|
visible: root.paneSwitchSupported
|
|
model: root.connectionTypes.map(t => root.typeLabels[t] || t)
|
|
currentIndex: Math.max(0, root.connectionTypes.indexOf(root.currentConnectionType))
|
|
selectionMode: "single"
|
|
onSelectionChanged: (index, selected) => {
|
|
if (!selected)
|
|
return;
|
|
root.selectedType = root.connectionTypes[index] || "wifi";
|
|
}
|
|
}
|
|
|
|
CcGroup {
|
|
visible: root.wifiMode
|
|
|
|
CcToggleRow {
|
|
iconName: NetworkService.wifiEnabled ? "wifi" : "wifi_off"
|
|
iconColor: NetworkService.wifiEnabled ? Theme.primary : Theme.surfaceText
|
|
text: I18n.tr("Wi-Fi", "wireless network, page and section title")
|
|
description: {
|
|
if (NetworkService.wifiToggling)
|
|
return NetworkService.wifiEnabled ? I18n.tr("Disabling WiFi...") : I18n.tr("Enabling WiFi...");
|
|
if (!NetworkService.wifiEnabled)
|
|
return I18n.tr("WiFi is off", "network status when the wifi radio is disabled");
|
|
return NetworkService.currentWifiSSID || I18n.tr("Not connected", "network status");
|
|
}
|
|
checked: NetworkService.wifiEnabled
|
|
toggling: NetworkService.wifiToggling
|
|
onToggled: NetworkService.toggleWifiRadio()
|
|
}
|
|
|
|
CcListRow {
|
|
id: hotspotRow
|
|
|
|
readonly property bool warnsWifiDrop: NetworkService.wifiEnabled && !root.hotspotWorking && !NetworkService.hotspotEnabled && NetworkService.hotspotWouldDisconnectWifi
|
|
|
|
visible: root.showHotspotRow
|
|
iconName: NetworkService.hotspotEnabled ? "wifi_tethering" : "wifi_tethering_off"
|
|
active: NetworkService.hotspotEnabled
|
|
title: I18n.tr("Hotspot", "hotspot control label")
|
|
subtitle: {
|
|
if (warnsWifiDrop)
|
|
return (NetworkService.hotspotSSID || I18n.tr("Ready", "hotspot ready status")) + " • " + I18n.tr("Will disconnect \"%1\"", "hotspot WiFi disconnection warning").arg(NetworkService.currentWifiSSID);
|
|
if (root.hotspotWorking)
|
|
return I18n.tr("Starting...", "hotspot activation status");
|
|
if (NetworkService.hotspotEnabled)
|
|
return NetworkService.hotspotSSID || I18n.tr("Running", "hotspot active status");
|
|
if (!NetworkService.wifiEnabled)
|
|
return I18n.tr("WiFi disabled", "hotspot unavailable status");
|
|
return NetworkService.hotspotSSID || I18n.tr("Ready", "hotspot ready status");
|
|
}
|
|
subtitleColor: warnsWifiDrop ? Theme.warning : Theme.surfaceVariantText
|
|
|
|
DSpinner {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
size: Theme.iconSizeMedium
|
|
strokeWidth: CcMetrics.spinnerStroke
|
|
color: Theme.primary
|
|
visible: root.hotspotWorking
|
|
running: visible
|
|
}
|
|
|
|
DToggle {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
hideText: true
|
|
visible: !root.hotspotWorking
|
|
checked: NetworkService.hotspotEnabled
|
|
onToggled: checked => {
|
|
if (!checked) {
|
|
NetworkService.stopHotspot();
|
|
return;
|
|
}
|
|
if (!NetworkService.wifiEnabled) {
|
|
root.explainHotspotNeedsWiFi();
|
|
return;
|
|
}
|
|
root.startHotspotWithConfirm();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CcEmptyState {
|
|
visible: root.wifiMode && NetworkService.wifiToggling
|
|
spinning: true
|
|
title: NetworkService.wifiEnabled ? I18n.tr("Disabling WiFi...") : I18n.tr("Enabling WiFi...")
|
|
}
|
|
|
|
CcEmptyState {
|
|
visible: root.wifiMode && !NetworkService.wifiEnabled && !NetworkService.wifiToggling
|
|
iconName: "wifi_off"
|
|
title: I18n.tr("WiFi is off", "network status when the wifi radio is disabled")
|
|
}
|
|
|
|
CcEmptyState {
|
|
visible: root.wifiScanningEmpty
|
|
spinning: true
|
|
title: I18n.tr("Scanning...")
|
|
}
|
|
|
|
CcSectionLabel {
|
|
text: I18n.tr("Available networks")
|
|
visible: root.wifiListVisible
|
|
}
|
|
|
|
CcGroup {
|
|
visible: root.ethernetMode && root.networkManager && DMSService.apiVersion > 10
|
|
|
|
Repeater {
|
|
model: wiredConnectionsModel
|
|
|
|
CcListRow {
|
|
id: wiredRow
|
|
|
|
required property var modelData
|
|
|
|
iconName: "lan"
|
|
active: modelData.isActive
|
|
title: modelData.id || I18n.tr("Unknown Config")
|
|
subtitle: active ? I18n.tr("Connected") : I18n.tr("Available")
|
|
clickable: true
|
|
onClicked: {
|
|
if (modelData.uuid === NetworkService.ethernetConnectionUuid)
|
|
return;
|
|
NetworkService.connectToSpecificWiredConfig(modelData.uuid);
|
|
}
|
|
|
|
DActionButton {
|
|
id: wiredOptionsButton
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
buttonSize: Theme.buttonHeightXS
|
|
iconSize: Theme.iconSizeMedium
|
|
iconName: "more_horiz"
|
|
Accessible.name: I18n.tr("Options")
|
|
iconColor: Theme.surfaceText
|
|
onClicked: root.openWiredMenu(wiredRow.modelData, wiredOptionsButton)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CcGroup {
|
|
visible: root.cellularMode && root.networkManager
|
|
|
|
CcToggleRow {
|
|
iconName: "network_cell"
|
|
iconColor: NetworkService.cellularEnabled ? Theme.primary : Theme.surfaceText
|
|
text: I18n.tr("Cellular")
|
|
description: {
|
|
if (NetworkService.cellularToggling)
|
|
return NetworkService.cellularEnabled ? I18n.tr("Disabling cellular...") : I18n.tr("Enabling cellular...");
|
|
if (!NetworkService.cellularHardwareEnabled)
|
|
return I18n.tr("Unavailable");
|
|
return NetworkService.cellularEnabled ? "" : I18n.tr("Disabled");
|
|
}
|
|
checked: NetworkService.cellularEnabled
|
|
enabled: NetworkService.cellularHardwareEnabled
|
|
toggling: NetworkService.cellularToggling
|
|
onToggled: NetworkService.toggleCellularRadio()
|
|
}
|
|
}
|
|
|
|
CcEmptyState {
|
|
visible: root.cellularMode && NetworkService.cellularToggling
|
|
spinning: true
|
|
title: NetworkService.cellularEnabled ? I18n.tr("Disabling cellular...") : I18n.tr("Enabling cellular...")
|
|
}
|
|
|
|
CcGroup {
|
|
visible: root.cellularMode && root.networkManager && NetworkService.cellularEnabled && !NetworkService.cellularToggling && (cellularDevices.count > 0 || cellularConnections.count > 0)
|
|
|
|
Repeater {
|
|
id: cellularDevices
|
|
model: (NetworkService.cellularConnections?.length ?? 0) > 0 ? [] : (NetworkService.cellularDevices || [])
|
|
|
|
CcListRow {
|
|
id: cellularDeviceRow
|
|
|
|
required property var modelData
|
|
|
|
iconName: "network_cell"
|
|
active: modelData.connected || false
|
|
title: modelData.description || modelData.name || I18n.tr("Unknown")
|
|
subtitle: active ? I18n.tr("Connected") : (modelData.state || I18n.tr("Available"))
|
|
clickable: true
|
|
onClicked: NetworkService.toggleNetworkConnection("cellular")
|
|
|
|
DActionButton {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
buttonSize: Theme.buttonHeightXS
|
|
iconSize: Theme.iconSizeMedium
|
|
iconName: cellularDeviceRow.active ? "link_off" : "link"
|
|
tooltipText: cellularDeviceRow.active ? I18n.tr("Disconnect") : I18n.tr("Connect")
|
|
iconColor: cellularDeviceRow.active ? Theme.error : Theme.primary
|
|
onClicked: NetworkService.toggleNetworkConnection("cellular")
|
|
}
|
|
}
|
|
}
|
|
|
|
Repeater {
|
|
id: cellularConnections
|
|
model: cellularConnectionsModel
|
|
|
|
CcListRow {
|
|
id: cellularRow
|
|
|
|
required property var modelData
|
|
|
|
iconName: "network_cell"
|
|
active: modelData.isActive
|
|
title: modelData.id || I18n.tr("Unknown")
|
|
subtitle: active ? I18n.tr("Connected") : (modelData.type || I18n.tr("Available"))
|
|
clickable: !active
|
|
onClicked: NetworkService.connectToSpecificCellularConfig(modelData.uuid)
|
|
|
|
DActionButton {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
buttonSize: Theme.buttonHeightXS
|
|
iconSize: Theme.iconSizeMedium
|
|
iconName: cellularRow.active ? "link_off" : "link"
|
|
tooltipText: cellularRow.active ? I18n.tr("Disconnect") : I18n.tr("Connect")
|
|
iconColor: cellularRow.active ? Theme.error : Theme.primary
|
|
onClicked: {
|
|
if (cellularRow.active) {
|
|
NetworkService.toggleNetworkConnection("cellular");
|
|
return;
|
|
}
|
|
NetworkService.connectToSpecificCellularConfig(cellularRow.modelData.uuid);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CcEmptyState {
|
|
visible: root.cellularMode && NetworkService.cellularEnabled && !NetworkService.cellularToggling && (NetworkService.cellularDevices?.length ?? 0) === 0 && cellularConnectionsModel.values.length === 0
|
|
iconName: "network_cell"
|
|
title: I18n.tr("No devices found")
|
|
}
|
|
}
|
|
|
|
delegate: CcListRow {
|
|
id: wifiRow
|
|
|
|
required property var modelData
|
|
required property int index
|
|
|
|
readonly property bool isConnected: modelData.ssid === NetworkService.currentWifiSSID
|
|
readonly property bool isConnecting: NetworkService.isWifiConnecting && NetworkService.connectingSSID === modelData.ssid
|
|
readonly property int signalStrength: modelData.signal || 0
|
|
readonly property bool sharesQrCode: modelData.secured && modelData.saved && !(modelData.enterprise || false)
|
|
|
|
width: pageList.width
|
|
topRadius: index === 0 ? Theme.groupedListOuterRadius : Theme.groupedListInnerRadius
|
|
bottomRadius: index === pageList.count - 1 ? Theme.groupedListOuterRadius : Theme.groupedListInnerRadius
|
|
iconName: {
|
|
if (isConnecting)
|
|
return "";
|
|
if (signalStrength >= CcMetrics.wifiSignalStrong)
|
|
return "wifi";
|
|
return signalStrength >= CcMetrics.wifiSignalBucket ? "wifi_2_bar" : "wifi_1_bar";
|
|
}
|
|
active: isConnected
|
|
title: modelData.ssid || I18n.tr("Unknown Network")
|
|
subtitle: {
|
|
const parts = [];
|
|
if (isConnecting)
|
|
parts.push(I18n.tr("Connecting..."));
|
|
else if (isConnected)
|
|
parts.push(I18n.tr("Connected"));
|
|
else
|
|
parts.push(modelData.secured ? I18n.tr("Secured") : I18n.tr("Open", "network security type", true));
|
|
if (modelData.saved)
|
|
parts.push(I18n.tr("Saved", "wifi network status, network has a saved profile", true));
|
|
parts.push(signalStrength + "%");
|
|
return parts.join(" • ");
|
|
}
|
|
subtitleColor: isConnecting ? Theme.warning : Theme.surfaceVariantText
|
|
clickable: true
|
|
onClicked: {
|
|
if (isConnected || NetworkService.isWifiConnecting)
|
|
return;
|
|
WifiConnectionActions.connectToNetwork(modelData, {
|
|
connected: isConnected
|
|
});
|
|
}
|
|
|
|
leading: Loader {
|
|
active: wifiRow.isConnecting
|
|
sourceComponent: DSpinner {
|
|
size: Theme.iconSizeMedium
|
|
strokeWidth: CcMetrics.spinnerStroke
|
|
color: Theme.warning
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
active: wifiRow.sharesQrCode
|
|
sourceComponent: DActionButton {
|
|
buttonSize: Theme.buttonHeightXS
|
|
iconSize: Theme.iconSizeMedium
|
|
iconName: "qr_code"
|
|
tooltipText: I18n.tr("Show QR Code")
|
|
iconColor: Theme.surfaceText
|
|
onClicked: PopoutService.showWifiQRCodeModal(wifiRow.modelData.ssid)
|
|
}
|
|
}
|
|
|
|
CcPinChip {
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
pinned: root.pinnedNetworks.includes(wifiRow.modelData.ssid)
|
|
onToggled: root.togglePin(wifiRow.modelData.ssid)
|
|
}
|
|
|
|
DActionButton {
|
|
id: wifiOptionsButton
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
buttonSize: Theme.buttonHeightXS
|
|
iconSize: Theme.iconSizeMedium
|
|
iconName: "more_horiz"
|
|
Accessible.name: I18n.tr("Options")
|
|
iconColor: Theme.surfaceText
|
|
onClicked: root.openWifiMenu(wifiRow.modelData, wifiRow.isConnected, wifiRow.isConnecting, wifiOptionsButton)
|
|
}
|
|
}
|
|
}
|
|
|
|
CcMenu {
|
|
id: wifiMenu
|
|
transientSurfaceTracker: root.transientSurfaceTracker
|
|
}
|
|
|
|
CcMenu {
|
|
id: wiredMenu
|
|
transientSurfaceTracker: root.transientSurfaceTracker
|
|
}
|
|
|
|
Loader {
|
|
id: networkInfoModalLoader
|
|
active: false
|
|
sourceComponent: NetworkInfoModal {}
|
|
}
|
|
|
|
Loader {
|
|
id: networkWiredInfoModalLoader
|
|
active: false
|
|
sourceComponent: NetworkInfoModal {
|
|
wired: true
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
id: hotspotConfirmLoader
|
|
active: false
|
|
sourceComponent: ConfirmModal {}
|
|
}
|
|
}
|