1404 lines
64 KiB
QML
1404 lines
64 KiB
QML
import QtQuick
|
||
import QtQuick.Layouts
|
||
import QtQuick.Controls
|
||
import org.kde.kirigami as Kirigami
|
||
import org.kde.plasma.core as PlasmaCore
|
||
import org.kde.plasma.components as PlasmaComponents
|
||
import org.kde.plasma.extras as PlasmaExtras
|
||
import org.kde.plasma.plasmoid
|
||
|
||
PlasmoidItem {
|
||
id: root
|
||
|
||
Plasmoid.title: "MeowRelay"
|
||
|
||
// compactRepresentation extra content
|
||
property var iflag: getFlag(current)
|
||
property var iflag_extra: getFlag(current) + current
|
||
|
||
// extra
|
||
hideOnWindowDeactivate: !plasmoid.configuration.isPinned
|
||
|
||
property var scrollbartype: Plasmoid.configuration.SBdisplay ? ScrollBar.AsNeeded : ScrollBar.AlwaysOff
|
||
|
||
//me/profile
|
||
property var profileData: null
|
||
|
||
property string user: profileData ? profileData.user : ""
|
||
property bool is_admin: profileData ? profileData.user_data.is_admin : false
|
||
property bool share: profileData ? profileData.user_data.share : false
|
||
property bool ebalka: profileData ? profileData.ebalka : false
|
||
property string current_device: profileData ? profileData.current_device : ""
|
||
property string current: profileData ? profileData.current : ""
|
||
property string provider: profileData ? profileData.provider : ""
|
||
property string ip: profileData ? profileData.ip : ""
|
||
property var features: profileData ? profileData.features : null
|
||
property var devices: profileData ? profileData.devices : null
|
||
|
||
//routes
|
||
property var routesData: null
|
||
|
||
//stats
|
||
property var statsData: null
|
||
|
||
//firewall
|
||
property var firewallData: null
|
||
property bool firewallAccess: firewallData ? (firewallData.state === 0) : false
|
||
property bool firewallEnabled: false
|
||
|
||
property double uptime: statsData ? statsData.uptime : 0
|
||
property var servers: statsData ? statsData.servers : null
|
||
|
||
// tabs
|
||
ListModel {
|
||
id: tabs
|
||
ListElement {
|
||
name: "Route"
|
||
visible: true
|
||
}
|
||
ListElement {
|
||
name: "Devices"
|
||
visible: true
|
||
}
|
||
ListElement {
|
||
name: "Firewall"
|
||
visible: false
|
||
}
|
||
ListElement {
|
||
name: "Stats"
|
||
visible: true
|
||
}
|
||
ListElement {
|
||
name: "Features"
|
||
visible: true
|
||
}
|
||
}
|
||
|
||
// tabs json responses
|
||
ListModel { id: routeModel }
|
||
ListModel { id: statsModel }
|
||
ListModel { id: profileModel }
|
||
ListModel { id: devicesModel }
|
||
ListModel { id: featuresModel }
|
||
ListModel { id: firewallModel }
|
||
ListModel { id: ownedipsModel }
|
||
ListModel { id: ownedlocalipsModel }
|
||
|
||
// buttons blocker (antispam)
|
||
property int isLoadingItems: 0
|
||
property bool isLoading: false // колясочные технологии, по итогу юзается токо isLoadingItems
|
||
property bool isBlocked: false
|
||
property bool shareBlocked: false
|
||
property bool ebalkaBlocked: false
|
||
property bool refreshBlocked: false
|
||
property bool countriesBlocked: false
|
||
property bool devicesBlocked: false
|
||
property bool featuresBlocked: false
|
||
property bool firewallBlocked: false
|
||
property bool timeouted: false
|
||
|
||
onIsLoadingItemsChanged: {
|
||
if (isLoadingItems > 0) {
|
||
isLoading = true
|
||
}
|
||
else if (isLoadingItems < 0) {
|
||
isLoading = false
|
||
isLoadingItems = 0
|
||
}
|
||
else {
|
||
isLoading = false
|
||
}
|
||
}
|
||
|
||
// flags
|
||
function getFlag(code) {
|
||
if (!code || code.length !== 2) return '❔';
|
||
let upper = code.toUpperCase();
|
||
let c1 = upper.charCodeAt(0) + 127397;
|
||
let c2 = upper.charCodeAt(1) + 127397;
|
||
return String.fromCodePoint(c1, c2);
|
||
}
|
||
|
||
// traffic
|
||
function formatTraffic(bytes) {
|
||
if (bytes === 0) return "0 B";
|
||
var units = ["B", "KB", "MB", "GB", "TB"];
|
||
var i = Math.floor(Math.log(bytes) / Math.log(1024));
|
||
var size = (bytes / Math.pow(1024, i)).toFixed(1);
|
||
return parseFloat(size) + " " + units[i];
|
||
}
|
||
|
||
Timer {
|
||
id: meowRelayWatchdog
|
||
interval: 10000
|
||
repeat: false
|
||
onTriggered: {
|
||
console.error("MeowRelay unreachable!") //ваша няшка умерла
|
||
timeouted = true
|
||
isBlocked = false
|
||
isLoadingItems = 0
|
||
countriesBlocked = true
|
||
shareBlocked = true
|
||
ebalkaBlocked = true
|
||
devicesBlocked = true
|
||
featuresBlocked = true
|
||
firewallBlocked = true
|
||
Plasmoid.configuration.OnErrorRefresh ? (
|
||
meowRelayWatchdog.start(),
|
||
isLoadingItems += Plasmoid.configuration.BIrefresh,
|
||
//isBlocked = true,
|
||
superWorker.sendMessage({ "action": "fetch_routes" }),
|
||
superWorker.sendMessage({ "action": "fetch_profile" }),
|
||
superWorker.sendMessage({ "action": "fetch_stats" }),
|
||
superWorker.sendMessage({ "action": "fetch_firewall" }),
|
||
fetchRoutesTimer.restart(),
|
||
fetchProfileTimer.restart(),
|
||
fetchStatsTimer.restart()
|
||
) : null
|
||
}
|
||
}
|
||
Timer {
|
||
id: meowRelayWatchdogRoutes
|
||
interval: 10000
|
||
repeat: false
|
||
onTriggered: {
|
||
console.error("MeowRelay unreachable!") //ваша няшка умерла
|
||
timeouted = true
|
||
refreshBlocked = false
|
||
Plasmoid.configuration.OnErrorRefresh ? (
|
||
meowRelayWatchdogRoutes.start(),
|
||
isLoadingItems += Plasmoid.configuration.BIrefresh,
|
||
//isBlocked = true,
|
||
superWorker.sendMessage({ "action": "fetch_routes" }),
|
||
fetchRoutesTimer.restart()
|
||
) : null
|
||
}
|
||
}
|
||
Timer {
|
||
id: meowRelayWatchdogProfile
|
||
interval: 10000
|
||
repeat: false
|
||
onTriggered: {
|
||
console.error("MeowRelay unreachable!") //ваша няшка умерла
|
||
timeouted = true
|
||
refreshBlocked = false
|
||
Plasmoid.configuration.OnErrorRefresh ? (
|
||
meowRelayWatchdogProfile.start(),
|
||
isLoadingItems += Plasmoid.configuration.BIrefresh,
|
||
//isBlocked = true,
|
||
superWorker.sendMessage({ "action": "fetch_profile" }),
|
||
fetchProfileTimer.restart()
|
||
) : null
|
||
}
|
||
}
|
||
Timer {
|
||
id: meowRelayWatchdogStats
|
||
interval: 10000
|
||
repeat: false
|
||
onTriggered: {
|
||
console.error("MeowRelay unreachable!") //ваша няшка умерла
|
||
timeouted = true
|
||
refreshBlocked = false
|
||
Plasmoid.configuration.OnErrorRefresh ? (
|
||
meowRelayWatchdogStats.start(),
|
||
isLoadingItems += Plasmoid.configuration.BIrefresh,
|
||
//isBlocked = true,
|
||
superWorker.sendMessage({ "action": "fetch_stats" }),
|
||
fetchStatsTimer.restart()
|
||
) : null
|
||
}
|
||
}
|
||
Timer {
|
||
id: meowRelayPing
|
||
interval: Plasmoid.configuration.AutoPingInt * 1000
|
||
running: Plasmoid.configuration.AutoPing
|
||
repeat: false
|
||
onTriggered: {
|
||
superWorker.sendMessage({ "action": "ping" })
|
||
console.log("MeowRelay ping pong")
|
||
}
|
||
}
|
||
|
||
// раб в отдельном потоке чтобы кде не фризило
|
||
WorkerScript {
|
||
id: superWorker
|
||
source: "worker.mjs"
|
||
|
||
property var handlers: ({
|
||
"fetch_routes": ({ data }) => {
|
||
routeModel.clear();
|
||
routesData = data;
|
||
for (let i = 0; i < data.length; i++) {
|
||
routeModel.append(data[i]);
|
||
};
|
||
if (Plasmoid.configuration.BIrefresh || Plasmoid.configuration.BIautoupdate) {
|
||
isLoadingItems -= 1
|
||
};
|
||
meowRelayWatchdogRoutes.stop();
|
||
refreshBlocked = false;
|
||
timeouted = false;
|
||
},
|
||
"fetch_stats": ({ data }) => {
|
||
statsModel.clear();
|
||
statsData = data;
|
||
var serverArray = [];
|
||
for (var Name in servers) {
|
||
if (servers.hasOwnProperty(Name)) {
|
||
var item = servers[Name];
|
||
item.name = Name;
|
||
item.pingString = item.ping.join(" ");
|
||
item.trafficString = item.traffic.join(" ");
|
||
item.speedString = item.speed.join(" ");
|
||
serverArray.push(item);
|
||
}
|
||
}
|
||
serverArray.sort(function(a, b) {
|
||
return b.connected - a.connected;
|
||
});
|
||
for (let i = 0; i < serverArray.length; i++) {
|
||
statsModel.append(serverArray[i]);
|
||
};
|
||
if (Plasmoid.configuration.BIrefresh || Plasmoid.configuration.BIautoupdate) {
|
||
isLoadingItems -= 1
|
||
};
|
||
meowRelayWatchdogStats.stop();
|
||
refreshBlocked = false;
|
||
timeouted = false;
|
||
},
|
||
"fetch_profile": ({ data }) => {
|
||
profileModel.clear();
|
||
devicesModel.clear();
|
||
featuresModel.clear();
|
||
ownedlocalipsModel.clear();
|
||
profileData = data;
|
||
for (let i = 0; i < data.length; i++) {
|
||
profileModel.append(data[i]);
|
||
}
|
||
for (let i = 0; i < data.devices.length; i++) {
|
||
devicesModel.append(data.devices[i])
|
||
}
|
||
if (Array.isArray(data.devices)) {
|
||
data.devices.forEach(function(device) {
|
||
ownedlocalipsModel.append({ "ip": device.ip });
|
||
});
|
||
}
|
||
for (let i = 0; i < data.features.length; i++) {
|
||
featuresModel.append(data.features[i])
|
||
if (data.features[i].name == "FEATURE_PORTCONFIGURATOR") {
|
||
firewallEnabled = data.features[i].value
|
||
tabs.setProperty(2, "visible", firewallEnabled)
|
||
}
|
||
}
|
||
if (Plasmoid.configuration.BIrefresh || Plasmoid.configuration.BIautoupdate) {
|
||
isLoadingItems -= 1
|
||
}
|
||
meowRelayWatchdog.stop();
|
||
meowRelayWatchdogProfile.stop();
|
||
timeouted = false;
|
||
isBlocked = false;
|
||
refreshBlocked = false;
|
||
countriesBlocked = false;
|
||
shareBlocked = false;
|
||
ebalkaBlocked = false;
|
||
devicesBlocked = false;
|
||
featuresBlocked = false;
|
||
},
|
||
"fetch_firewall": ({ data }) => {
|
||
firewallModel.clear();
|
||
ownedipsModel.clear();
|
||
firewallData = data;
|
||
if (data.state === 0 && data.own && Array.isArray(data.own)) {
|
||
data.own.forEach(function(ip) {
|
||
ownedipsModel.append({ ip });
|
||
});
|
||
}
|
||
if (data.state === 0 && data.rules) {
|
||
Object.keys(data.rules).forEach(function(ipKey) {
|
||
var rulesArray = data.rules[ipKey];
|
||
|
||
rulesArray.forEach(function(rule) {
|
||
firewallModel.append({
|
||
"ip": ipKey,
|
||
"dst": rule.dst,
|
||
"port": rule.port,
|
||
"local_port": rule.local_port,
|
||
"proto": rule.proto,
|
||
"packets": (rule.packets ? rule.packets : 0),
|
||
"bytes": (rule.bytes ? rule.bytes : 0)
|
||
});
|
||
});
|
||
});
|
||
}
|
||
firewallBlocked = false;
|
||
if (Plasmoid.configuration.BIpostfirewall) {
|
||
isLoadingItems -= 1
|
||
};
|
||
},
|
||
"post_country": ({ status }) => {
|
||
if (status === 200) {
|
||
superWorker.sendMessage({ "action": "fetch_profile" })
|
||
//done
|
||
}
|
||
else {
|
||
superWorker.sendMessage({ "actions": "fetch_routes" })
|
||
//error
|
||
};
|
||
if (Plasmoid.configuration.BIpostcountry) {
|
||
isLoadingItems -= 1
|
||
}
|
||
},
|
||
"post_share": ({ status }) => {
|
||
if (status === 200) {
|
||
superWorker.sendMessage({ "action": "fetch_profile" })
|
||
//done
|
||
}
|
||
else {
|
||
superWorker.sendMessage({ "action": "fetch_profile" })
|
||
// share = !share
|
||
//error
|
||
};
|
||
if (Plasmoid.configuration.BIpostshare) {
|
||
isLoadingItems -= 1
|
||
}
|
||
shareBlocked = false;
|
||
},
|
||
"post_ebalka": ({ status, ip }) => {
|
||
if (status === 200 && ip != null) {
|
||
superWorker.sendMessage({ "action": "fetch_profile" })
|
||
//done
|
||
}
|
||
else {
|
||
superWorker.sendMessage({ "action": "fetch_profile" }) // кофе
|
||
//error
|
||
};
|
||
if (Plasmoid.configuration.BIpostebalka) {
|
||
isLoadingItems -= 1
|
||
}
|
||
if (Plasmoid.configuration.BIdevicesupdate) {
|
||
isLoadingItems -= 1
|
||
}
|
||
ebalkaBlocked = false;
|
||
devicesBlocked = false;
|
||
},
|
||
"post_name": ({ status }) => {
|
||
if (status === 200) {
|
||
superWorker.sendMessage({ "action": "fetch_profile" })
|
||
//done
|
||
}
|
||
else {
|
||
//error
|
||
};
|
||
if (Plasmoid.configuration.BIdevicesupdate) {
|
||
isLoadingItems -= 1
|
||
}
|
||
devicesBlocked = false;
|
||
},
|
||
"post_feature": ({ status }) => {
|
||
superWorker.sendMessage({ "action": "fetch_profile" });
|
||
if (Plasmoid.configuration.BIfeaturesupdate) {
|
||
isLoadingItems -= 1
|
||
}
|
||
featuresBlocked = false;
|
||
},
|
||
"post_idconnect": ({ status }) => {
|
||
superWorker.sendMessage({ "action": "fetch_profile" });
|
||
superWorker.sendMessage({ "action": "fetch_routes" });
|
||
if (Plasmoid.configuration.BIpostcountry) {
|
||
isLoadingItems -= 1
|
||
}
|
||
},
|
||
"post_ruleadd": ({ status }) => {
|
||
superWorker.sendMessage({ "action": "fetch_firewall" });
|
||
if (Plasmoid.configuration.BIpostfirewall) {
|
||
isLoadingItems -= 1
|
||
}
|
||
},
|
||
"post_ruledrop": ({ status }) => {
|
||
superWorker.sendMessage({ "action": "fetch_firewall" });
|
||
if (Plasmoid.configuration.BIpostfirewall) {
|
||
isLoadingItems -= 1
|
||
}
|
||
}
|
||
})
|
||
|
||
onMessage: (msg) => {
|
||
if (handlers[msg.action]) {
|
||
handlers[msg.action](msg);
|
||
}
|
||
}
|
||
}
|
||
|
||
// init fetch
|
||
Component.onCompleted: {
|
||
isLoadingItems += Plasmoid.configuration.BIinit
|
||
isBlocked = true
|
||
meowRelayWatchdog.start()
|
||
superWorker.sendMessage({ "action": "fetch_routes" })
|
||
superWorker.sendMessage({ "action": "fetch_stats" })
|
||
superWorker.sendMessage({ "action": "fetch_profile" })
|
||
superWorker.sendMessage({ "action": "fetch_firewall" })
|
||
fetchRoutesTimer.start()
|
||
fetchStatsTimer.start()
|
||
fetchProfileTimer.start()
|
||
// meowRelayPing.start()
|
||
}
|
||
|
||
// autoupdate fetch
|
||
Timer {
|
||
id: fetchRoutesTimer
|
||
interval: (Plasmoid.configuration.RoutesUpInt * 60000)
|
||
running: Plasmoid.configuration.RoutesAutoUp
|
||
repeat: true
|
||
triggeredOnStart: false
|
||
onTriggered: {
|
||
//refreshBlocked = true
|
||
isLoadingItems += Plasmoid.configuration.BIautoupdate
|
||
meowRelayWatchdogRoutes.start()
|
||
superWorker.sendMessage({ "action": "fetch_routes" })
|
||
}
|
||
}
|
||
Timer {
|
||
id: fetchStatsTimer
|
||
interval: (Plasmoid.configuration.StatsUpInt * 60000)
|
||
running: Plasmoid.configuration.StatsAutoUp
|
||
repeat: true
|
||
triggeredOnStart: false
|
||
onTriggered: {
|
||
//refreshBlocked = true
|
||
isLoadingItems += Plasmoid.configuration.BIautoupdate
|
||
meowRelayWatchdogStats.start()
|
||
superWorker.sendMessage({ "action": "fetch_stats" })
|
||
}
|
||
}
|
||
Timer {
|
||
id: fetchProfileTimer
|
||
interval: (Plasmoid.configuration.ProfileUpInt * 60000)
|
||
running: Plasmoid.configuration.ProfileAutoUp
|
||
repeat: true
|
||
triggeredOnStart: false
|
||
onTriggered: {
|
||
//refreshBlocked = true
|
||
isLoadingItems += Plasmoid.configuration.BIautoupdate
|
||
meowRelayWatchdogProfile.start()
|
||
superWorker.sendMessage({ "action": "fetch_profile" })
|
||
}
|
||
}
|
||
|
||
compactRepresentation: Compact {}
|
||
|
||
fullRepresentation: PlasmaExtras.Representation {
|
||
//id: fullRoot
|
||
Layout.minimumWidth: Kirigami.Units.gridUnit * 25
|
||
Layout.minimumHeight: Kirigami.Units.gridUnit * 30
|
||
Layout.preferredWidth: Kirigami.Units.gridUnit * 25
|
||
Layout.preferredHeight: Kirigami.Units.gridUnit * 30
|
||
//spacing: 0
|
||
|
||
header: PlasmaExtras.PlasmoidHeading {
|
||
// Make this toolbar's buttons align vertically with the ones above
|
||
rightPadding: -1
|
||
// Allow tabbar to touch the header's bottom border
|
||
bottomPadding: -bottomInset
|
||
|
||
contentItem: ColumnLayout {
|
||
spacing: Kirigami.Units.smallSpacing
|
||
|
||
// row 1 (name)
|
||
RowLayout {
|
||
Layout.fillWidth: true
|
||
|
||
PlasmaExtras.Heading {
|
||
text: " " + plasmoid.title
|
||
level: 1
|
||
Layout.fillWidth: false
|
||
elide: Text.ElideRight
|
||
}
|
||
Rectangle {
|
||
height: Kirigami.Units.gridUnit
|
||
Layout.alignment: AlignVCenter
|
||
width: 1
|
||
color: PlasmaCore.Theme.dividerColor
|
||
opacity: 0.7
|
||
}
|
||
PlasmaExtras.Heading {
|
||
text: (user ? user : "unknown")
|
||
opacity: 0.7
|
||
level: 1
|
||
Layout.fillWidth: true
|
||
elide: Text.ElideRight
|
||
}
|
||
|
||
// config button
|
||
PlasmaComponents.ToolButton {
|
||
id: configButton
|
||
icon.name: "configure"
|
||
display: ToolButton.IconOnly
|
||
onClicked: plasmoid.internalAction("configure").trigger()
|
||
ToolTip.text: i18n("Configure")
|
||
ToolTip.visible: hovered
|
||
ToolTip.delay: Kirigami.Units.toolTipDelay
|
||
KeyNavigation.right: pinButton
|
||
}
|
||
|
||
// pin button
|
||
PlasmaComponents.ToolButton {
|
||
id: pinButton
|
||
icon.name: "window-pin"
|
||
display: ToolButton.IconOnly
|
||
checkable: true
|
||
checked: plasmoid.configuration.isPinned
|
||
down: checked
|
||
onToggled: plasmoid.configuration.isPinned = checked
|
||
ToolTip.text: i18n("Keep Open")
|
||
ToolTip.visible: hovered
|
||
ToolTip.delay: Kirigami.Units.toolTipDelay
|
||
KeyNavigation.left: configButton
|
||
visible: plasmoid.formFactor === 2 || plasmoid.formFactor === 3
|
||
enabled: visible
|
||
}
|
||
}
|
||
|
||
// row 2 (tabs)
|
||
PlasmaComponents.TabBar {
|
||
id: mainTabBar
|
||
Layout.fillWidth: true
|
||
|
||
Repeater {
|
||
model: tabs
|
||
delegate: PlasmaComponents.TabButton {
|
||
text: model.name
|
||
visible: model.visible
|
||
width: firewallEnabled ? (mainTabBar.width / 5) : ((model.name == "Firewall") ? 0 : (mainTabBar.width / 4)) // это пизда или нармалды
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Footer
|
||
footer: PlasmaExtras.PlasmoidHeading {
|
||
id: footerItem
|
||
ColumnLayout {
|
||
anchors.fill: parent
|
||
|
||
PlasmaComponents.ProgressBar {
|
||
indeterminate: true
|
||
//visible: isLoading
|
||
visible: false
|
||
Layout.fillWidth: true
|
||
}
|
||
|
||
// Tab 3 util buttons
|
||
RowLayout {
|
||
spacing: Kirigami.Units.smallSpacing
|
||
visible: (mainTabBar.currentIndex === 2 && firewallAccess && firewallEnabled)
|
||
PlasmaComponents.ComboBox {
|
||
id: firewallProto
|
||
model: ["tcp", "udp"]
|
||
currentIndex: 0
|
||
}
|
||
Kirigami.ContextualHelpButton {
|
||
toolTipText: i18n(
|
||
'All ' + firewallProto.currentValue + ' traffic from ' + firewallIp.currentValue + ':' + firewallPortSpinner.value + ' will be forwarded to ' + firewallLocalIp.currentValue + ':' + firewallLocalPortSpinner.value
|
||
)
|
||
}
|
||
Item {
|
||
Layout.fillWidth: true
|
||
}
|
||
PlasmaComponents.Button {
|
||
text: "Update"
|
||
icon.name: "view-refresh"
|
||
enabled: !(isBlocked)
|
||
onClicked: {
|
||
isLoadingItems += Plasmoid.configuration.BIpostfirewall
|
||
firewallBlocked = true
|
||
superWorker.sendMessage({ "action": "fetch_firewall" })
|
||
}
|
||
}
|
||
PlasmaComponents.Button {
|
||
text: "Add"
|
||
enabled: !(isBlocked || firewallBlocked)
|
||
onClicked: {
|
||
isLoadingItems += Plasmoid.configuration.BIpostfirewall
|
||
firewallBlocked = true
|
||
superWorker.sendMessage({ "action": "post_ruleadd", "dst": firewallLocalIp.currentValue, "ext": firewallIp.currentValue, "local_port": firewallLocalPortSpinner.value, "port": firewallPortSpinner.value, "proto": firewallProto.currentValue })
|
||
}
|
||
}
|
||
}
|
||
RowLayout {
|
||
spacing: Kirigami.Units.smallSpacing
|
||
visible: (mainTabBar.currentIndex === 2 && firewallAccess && firewallEnabled)
|
||
PlasmaComponents.ComboBox {
|
||
id: firewallIp
|
||
model: ownedipsModel
|
||
currentIndex: 0
|
||
Connections {
|
||
target: ownedipsModel
|
||
|
||
function onCountChanged() {
|
||
if (ownedipsModel.count > 0) {
|
||
firewallIp.currentIndex = 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: ":"
|
||
font.bold: true
|
||
}
|
||
SpinBox {
|
||
id: firewallPortSpinner
|
||
from: 1
|
||
to: 65535
|
||
value: 1
|
||
}
|
||
Item {
|
||
Layout.fillWidth: true
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: "→"
|
||
font.bold: true
|
||
}
|
||
Item {
|
||
Layout.fillWidth: true
|
||
}
|
||
PlasmaComponents.ComboBox {
|
||
id: firewallLocalIp
|
||
model: ownedlocalipsModel
|
||
currentIndex: 0
|
||
Connections {
|
||
target: ownedlocalipsModel
|
||
|
||
function onCountChanged() {
|
||
if (ownedlocalipsModel.count > 0) {
|
||
firewallLocalIp.currentIndex = 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: ":"
|
||
font.bold: true
|
||
}
|
||
SpinBox {
|
||
id: firewallLocalPortSpinner
|
||
from: 1
|
||
to: 65535
|
||
value: 1
|
||
}
|
||
}
|
||
Rectangle {
|
||
visible: (mainTabBar.currentIndex === 2 && firewallAccess && firewallEnabled)
|
||
height: 1
|
||
Layout.alignment: AlignVCenter
|
||
Layout.fillWidth: true
|
||
color: PlasmaCore.Theme.dividerColor
|
||
opacity: 0.2
|
||
}
|
||
|
||
RowLayout {
|
||
spacing: Kirigami.Units.smallSpacing
|
||
PlasmaComponents.Label {
|
||
text: "Up:"
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: (Math.floor(uptime / 86400)) + "d " + (Math.floor((uptime % 86400) / 3600)) + "h " + (Math.floor(((uptime % 86400) % 3600) / 60)) + "m"
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
Item {
|
||
Layout.fillWidth: true
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: getFlag(current) + current
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: provider
|
||
opacity: 0.7
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
Rectangle {
|
||
height: Kirigami.Units.gridUnit
|
||
Layout.alignment: AlignVCenter
|
||
width: 1
|
||
color: PlasmaCore.Theme.dividerColor
|
||
opacity: 0.2
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: "Device:"
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: current_device
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
Rectangle {
|
||
height: Kirigami.Units.gridUnit
|
||
Layout.alignment: AlignVCenter
|
||
width: 1
|
||
color: PlasmaCore.Theme.dividerColor
|
||
opacity: 0.2
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: "Ip:"
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: ip
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
}
|
||
|
||
RowLayout {
|
||
|
||
PlasmaComponents.Button {
|
||
text: "Refresh"
|
||
icon.name: "view-refresh"
|
||
onClicked: {
|
||
meowRelayWatchdog.running ? meowRelayWatchdog.stop() : null
|
||
meowRelayWatchdog.start()
|
||
isLoadingItems += Plasmoid.configuration.BIrefresh
|
||
isBlocked = true
|
||
superWorker.sendMessage({ "action": "fetch_routes" })
|
||
superWorker.sendMessage({ "action": "fetch_profile" })
|
||
superWorker.sendMessage({ "action": "fetch_stats" })
|
||
superWorker.sendMessage({ "action": "fetch_firewall" })
|
||
fetchRoutesTimer.restart()
|
||
fetchProfileTimer.restart()
|
||
fetchStatsTimer.restart()
|
||
}
|
||
enabled: !(isBlocked || refreshBlocked)
|
||
Layout.fillWidth: false
|
||
}
|
||
PlasmaComponents.BusyIndicator {
|
||
running: isLoadingItems //isLoading
|
||
implicitWidth: 28
|
||
implicitHeight: 28
|
||
}
|
||
Kirigami.Icon {
|
||
source: "network-limited-symbolic"
|
||
visible: timeouted
|
||
implicitWidth: 30
|
||
implicitHeight: 30
|
||
//isMask: true
|
||
//active: mouseArea.containsMouse
|
||
}
|
||
Kirigami.ContextualHelpButton {
|
||
visible: timeouted
|
||
toolTipText: i18n(
|
||
"MeowRelay unreachable! (timeout)"
|
||
)
|
||
}
|
||
Item {
|
||
Layout.fillWidth: true
|
||
}
|
||
PlasmaComponents.Switch {
|
||
text: "Share"
|
||
checked: share
|
||
enabled: !(isBlocked || shareBlocked)
|
||
onClicked: {
|
||
isLoadingItems += Plasmoid.configuration.BIpostshare
|
||
shareBlocked = true
|
||
superWorker.sendMessage({ "action": "post_share", "bool": !share })
|
||
share = !share
|
||
}
|
||
}
|
||
Rectangle {
|
||
height: Kirigami.Units.gridUnit
|
||
Layout.alignment: AlignVCenter
|
||
width: 1
|
||
color: PlasmaCore.Theme.dividerColor
|
||
opacity: 0.2
|
||
}
|
||
PlasmaComponents.Switch {
|
||
text: "80% loss"
|
||
checked: ebalka
|
||
enabled: !(isBlocked || ebalkaBlocked)
|
||
onClicked: {
|
||
isLoadingItems += Plasmoid.configuration.BIpostebalka
|
||
ebalkaBlocked = true
|
||
superWorker.sendMessage({ "action": "post_ebalka", "bool": !ebalka, "ip": null })
|
||
ebalka = !ebalka
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
// Content
|
||
contentItem: Item {
|
||
StackLayout {
|
||
id: tabStack
|
||
anchors.fill: parent
|
||
currentIndex: mainTabBar.currentIndex
|
||
|
||
// Tab 1 Routes
|
||
Item {
|
||
PlasmaExtras.PlaceholderMessage {
|
||
anchors.centerIn: parent
|
||
text: "Connecting to\nMeowRelay"
|
||
iconName: "akregator-symbolic"
|
||
visible: routesData === null
|
||
}
|
||
PlasmaComponents.ScrollView {
|
||
id: routeScroll
|
||
anchors.fill: parent
|
||
ScrollBar.vertical.policy: scrollbartype
|
||
|
||
Column {
|
||
id: listContainer
|
||
width: routeScroll.availableWidth
|
||
spacing: 0
|
||
|
||
// countries
|
||
Repeater {
|
||
model: routeModel
|
||
delegate: PlasmaComponents.RadioDelegate {
|
||
width: listContainer.width
|
||
height: Kirigami.Units.gridUnit * 3
|
||
enabled: !countriesBlocked
|
||
checked: (model.code === current && model.provider === provider)
|
||
|
||
contentItem: RowLayout {
|
||
spacing: Kirigami.Units.largeSpacing
|
||
PlasmaComponents.Label {
|
||
horizontalAlignment: Text.AlignLeft
|
||
verticalAlignment: Text.AlignVCenter
|
||
wrapMode: Text.Wrap
|
||
font.pixelSize: 24
|
||
text: getFlag(model.code)
|
||
}
|
||
|
||
ColumnLayout {
|
||
spacing: 0
|
||
Layout.fillWidth: true
|
||
PlasmaComponents.Label {
|
||
text: model.name
|
||
font.bold: true
|
||
Layout.fillWidth: true
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: model.provider
|
||
font.pointSize: Kirigami.Theme.smallFont.pointSize
|
||
opacity: 0.7
|
||
Layout.fillWidth: true
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
}
|
||
}
|
||
onClicked: {
|
||
isLoadingItems += Plasmoid.configuration.BIpostcountry
|
||
superWorker.sendMessage({ "action": "post_country", "code": model.code, "provider": model.provider })
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Tab 2 Devices
|
||
Item {
|
||
PlasmaExtras.PlaceholderMessage {
|
||
anchors.centerIn: parent
|
||
text: "Connecting to\nMeowRelay"
|
||
iconName: "akregator-symbolic"
|
||
visible: devices === null
|
||
}
|
||
PlasmaComponents.ScrollView {
|
||
id: devicesScroll
|
||
anchors.fill: parent
|
||
ScrollBar.vertical.policy: scrollbartype
|
||
|
||
Column {
|
||
id: deviceListContainer
|
||
width: devicesScroll.availableWidth
|
||
spacing: Kirigami.Units.smallSpacing
|
||
Item {
|
||
width: deviceListContainer.width
|
||
height: Kirigami.Units.smallSpacing/2
|
||
}
|
||
|
||
// devices
|
||
Repeater {
|
||
model: devicesModel
|
||
delegate: PlasmaComponents.Button {
|
||
id: devicesButton
|
||
width: deviceListContainer.width
|
||
height: Kirigami.Units.gridUnit * 4
|
||
|
||
contentItem: RowLayout {
|
||
x: Kirigami.Units.largeSpacing
|
||
y: Kirigami.Units.largeSpacing
|
||
width: devicesButton.availableWidth
|
||
spacing: Kirigami.Units.smallSpacing
|
||
ColumnLayout {
|
||
spacing: 0
|
||
RowLayout {
|
||
Layout.fillWidth: true
|
||
PlasmaComponents.Label {
|
||
text: model.name
|
||
font.bold: true
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: "(LOSS 80%)"
|
||
color: "#f38ba8"
|
||
visible: model.ebalka
|
||
Layout.fillWidth: true
|
||
}
|
||
}
|
||
RowLayout {
|
||
PlasmaComponents.Label {
|
||
text: model.ip
|
||
//opacity: 0.7
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: "↓"
|
||
color: "#00ff00"
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: formatTraffic(model.rx)
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: "↑"
|
||
color: "#00aaff"
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: formatTraffic(model.tx)
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
}
|
||
RowLayout {
|
||
PlasmaComponents.Label {
|
||
text: getFlag(model.country)
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: model.country + " " + model.provider
|
||
opacity: 0.7
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: (model.online ? "online" : "offline")
|
||
color: (model.online ? "#a6e3a1" : "#f38ba8")
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
}
|
||
}
|
||
Item {
|
||
Layout.fillWidth: true
|
||
}
|
||
ColumnLayout {
|
||
RowLayout {
|
||
Item {
|
||
Layout.fillWidth: true
|
||
}
|
||
PlasmaComponents.Switch {
|
||
text: "80% loss"
|
||
checked: model.ebalka
|
||
enabled: !(isBlocked || devicesBlocked)
|
||
onClicked: {
|
||
isLoadingItems += Plasmoid.configuration.BIdevicesupdate
|
||
devicesBlocked = true
|
||
superWorker.sendMessage({ "action": "post_ebalka", "bool": !model.ebalka, "ip": model.ip })
|
||
// ebalka = !ebalka
|
||
}
|
||
}
|
||
}
|
||
RowLayout {
|
||
Item {
|
||
Layout.fillWidth: true
|
||
}
|
||
PlasmaComponents.Button {
|
||
id: menuButton
|
||
text: "Rename"
|
||
enabled: !(isBlocked || devicesBlocked)
|
||
PlasmaComponents.Menu {
|
||
id: inputMenu
|
||
padding: Kirigami.Units.largeSpacing
|
||
|
||
function confirmAction() {
|
||
superWorker.sendMessage({ "action": "post_name", "ip": model.ip, "name": textInput.text })
|
||
inputMenu.close();
|
||
textInput.text = "";
|
||
}
|
||
|
||
ColumnLayout {
|
||
spacing: Kirigami.Units.smallSpacing
|
||
RowLayout {
|
||
PlasmaComponents.Label {
|
||
text: "Enter new name:"
|
||
font.pixelSize: Kirigami.Units.gridUnit * 0.8
|
||
}
|
||
}
|
||
RowLayout {
|
||
PlasmaComponents.TextField {
|
||
id: textInput
|
||
placeholderText: (model.name).split(" ").slice(2).join(" ")
|
||
focus: true
|
||
onAccepted: inputMenu.confirmAction()
|
||
}
|
||
PlasmaComponents.Button {
|
||
icon.name: "dialog-ok-apply"
|
||
onClicked: inputMenu.confirmAction()
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
onClicked: {
|
||
inputMenu.open();
|
||
textInput.forceActiveFocus();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
//onClicked: {
|
||
//}
|
||
}
|
||
}
|
||
Item {
|
||
width: deviceListContainer.width
|
||
height: Kirigami.Units.smallSpacing/2
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Tab 3 Firewall
|
||
Item {
|
||
PlasmaExtras.PlaceholderMessage {
|
||
anchors.centerIn: parent
|
||
text: "Connecting to\nMeowRelay"
|
||
iconName: "akregator-symbolic"
|
||
visible: firewallData === null
|
||
}
|
||
PlasmaExtras.PlaceholderMessage {
|
||
anchors.centerIn: parent
|
||
text: "Nothing to see here"
|
||
iconName: "face-sad"
|
||
visible: (!firewallAccess && firewallData)
|
||
}
|
||
PlasmaComponents.ScrollView {
|
||
id: firewallScroll
|
||
anchors.fill: parent
|
||
ScrollBar.vertical.policy: scrollbartype
|
||
|
||
Column {
|
||
id: firewallListContainer
|
||
width: firewallScroll.availableWidth
|
||
spacing: Kirigami.Units.smallSpacing
|
||
Item {
|
||
width: firewallListContainer.width
|
||
height: Kirigami.Units.smallSpacing/2
|
||
}
|
||
|
||
// firewall
|
||
Repeater {
|
||
model: firewallModel
|
||
delegate: PlasmaComponents.Button {
|
||
id: firewallButton
|
||
width: firewallListContainer.width
|
||
height: Kirigami.Units.gridUnit * 4
|
||
|
||
contentItem: RowLayout {
|
||
x: Kirigami.Units.largeSpacing
|
||
y: Kirigami.Units.largeSpacing
|
||
width: firewallButton.availableWidth
|
||
spacing: Kirigami.Units.smallSpacing
|
||
ColumnLayout {
|
||
spacing: 0
|
||
RowLayout {
|
||
Layout.fillWidth: true
|
||
PlasmaComponents.Label {
|
||
text: model.ip + ":" + model.port
|
||
font.bold: true
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: "→"
|
||
font.bold: true
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: model.dst + ":" + model.local_port
|
||
font.bold: true
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: "(" + model.proto + ")"
|
||
opacity: 0.7
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
}
|
||
RowLayout {
|
||
Layout.fillWidth: true
|
||
PlasmaComponents.Label {
|
||
text: model.packets + " pcks /"
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: formatTraffic(model.bytes)
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
}
|
||
}
|
||
Item {
|
||
Layout.fillWidth: true
|
||
}
|
||
ColumnLayout {
|
||
spacing: 0
|
||
PlasmaComponents.Button {
|
||
id: dropFirewallButton
|
||
text: "Drop"
|
||
enabled: !(isBlocked || firewallBlocked)
|
||
onClicked: {
|
||
isLoadingItems += Plasmoid.configuration.BIpostfirewall
|
||
firewallBlocked = true
|
||
superWorker.sendMessage({ "action": "post_ruledrop", "dst": model.dst, "ext": model.ip, "local_port": model.local_port, "port": model.port, "proto": model.proto })
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
Item {
|
||
width: firewallListContainer.width
|
||
height: Kirigami.Units.smallSpacing/2
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Tab 4 Stats
|
||
Item {
|
||
PlasmaExtras.PlaceholderMessage {
|
||
anchors.centerIn: parent
|
||
text: "Connecting to\nMeowRelay"
|
||
iconName: "akregator-symbolic"
|
||
visible: statsData === null
|
||
}
|
||
PlasmaComponents.ScrollView {
|
||
id: statsScroll
|
||
anchors.fill: parent
|
||
ScrollBar.vertical.policy: scrollbartype
|
||
|
||
Column {
|
||
id: statsListContainer
|
||
width: statsScroll.availableWidth
|
||
spacing: Kirigami.Units.smallSpacing
|
||
Item {
|
||
width: statsListContainer.width
|
||
height: Kirigami.Units.smallSpacing/2
|
||
}
|
||
|
||
// stats
|
||
Repeater {
|
||
model: statsModel
|
||
delegate: PlasmaComponents.Button {
|
||
id: statsButton
|
||
width: statsListContainer.width
|
||
height: Kirigami.Units.gridUnit * 4
|
||
enabled: !(isBlocked || countriesBlocked)
|
||
|
||
contentItem: RowLayout {
|
||
x: Kirigami.Units.largeSpacing
|
||
y: Kirigami.Units.largeSpacing
|
||
width: statsButton.availableWidth
|
||
spacing: Kirigami.Units.smallSpacing
|
||
ColumnLayout {
|
||
spacing: 0
|
||
RowLayout {
|
||
Layout.fillWidth: true
|
||
PlasmaComponents.Label {
|
||
text: getFlag(model.country)
|
||
elide: Text.ElideRight
|
||
font.pixelSize: 16
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: model.name
|
||
font.bold: true
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: "Up: " + (Math.floor(model.uptime / 86400)) + "d " + (Math.floor((model.uptime % 86400) / 3600)) + "h " + (Math.floor(((model.uptime % 86400) % 3600) / 60)) + "m"
|
||
}
|
||
}
|
||
Item {
|
||
Layout.fillWidth: true
|
||
}
|
||
ColumnLayout {
|
||
spacing: 0
|
||
RowLayout {
|
||
Item {
|
||
Layout.fillWidth: true
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: model.connected + " peers (online: " + model.online + ")"
|
||
color: "#a6e3a1"
|
||
font.bold: true
|
||
}
|
||
}
|
||
RowLayout {
|
||
Item {
|
||
Layout.fillWidth: true
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: "↓"
|
||
color: "#00ff00"
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: formatTraffic(model.trafficString.split(" ")[0])
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: "(" + formatTraffic(model.speedString.split(" ")[0]) + ")"
|
||
opacity: 0.7
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: "↑"
|
||
color: "#00aaff"
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: formatTraffic(model.trafficString.split(" ")[1])
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: "(" + formatTraffic(model.speedString.split(" ")[1]) + ")"
|
||
opacity: 0.7
|
||
}
|
||
}
|
||
RowLayout {
|
||
Item {
|
||
Layout.fillWidth: true
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: model.pingString.split(" ").join(", ") + " ms"
|
||
color: "#a6e3a1"
|
||
font.bold: true
|
||
}
|
||
}
|
||
}
|
||
}
|
||
onClicked: {
|
||
isLoadingItems += Plasmoid.configuration.BIpostcountry
|
||
superWorker.sendMessage({ "action": "post_idconnect", "iface": model.name })
|
||
}
|
||
}
|
||
}
|
||
Item {
|
||
width: statsListContainer.width
|
||
height: Kirigami.Units.smallSpacing/2
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Tab 5 Features
|
||
Item {
|
||
PlasmaExtras.PlaceholderMessage {
|
||
anchors.centerIn: parent
|
||
text: "Connecting to\nMeowRelay"
|
||
iconName: "akregator-symbolic"
|
||
visible: features === null
|
||
}
|
||
PlasmaComponents.ScrollView {
|
||
id: featuresScroll
|
||
anchors.fill: parent
|
||
ScrollBar.vertical.policy: scrollbartype
|
||
|
||
Column {
|
||
id: featuresListContainer
|
||
width: featuresScroll.availableWidth
|
||
spacing: Kirigami.Units.smallSpacing
|
||
Item {
|
||
width: featuresListContainer.width
|
||
height: Kirigami.Units.smallSpacing/2
|
||
}
|
||
|
||
// features
|
||
Repeater {
|
||
model: featuresModel
|
||
delegate: PlasmaComponents.Button {
|
||
id: featuresButton
|
||
width: featuresListContainer.width
|
||
height: Kirigami.Units.gridUnit * 4
|
||
|
||
contentItem: RowLayout {
|
||
x: Kirigami.Units.largeSpacing
|
||
y: Kirigami.Units.largeSpacing
|
||
width: featuresButton.availableWidth
|
||
spacing: Kirigami.Units.smallSpacing
|
||
ColumnLayout {
|
||
spacing: 2
|
||
Layout.fillWidth: true
|
||
PlasmaComponents.Label {
|
||
text: model.name
|
||
elide: Text.ElideRight
|
||
//font.pixelSize: 16
|
||
verticalAlignment: Text.AlignVCenter
|
||
}
|
||
PlasmaComponents.Label {
|
||
text: model.desc
|
||
wrapMode: Text.Wrap
|
||
opacity: 0.7
|
||
//font.bold: true
|
||
elide: Text.ElideRight
|
||
verticalAlignment: Text.AlignVCenter
|
||
Layout.fillWidth: true
|
||
}
|
||
}
|
||
PlasmaComponents.Switch {
|
||
checked: model.value
|
||
enabled: !(isBlocked || featuresBlocked)
|
||
onClicked: {
|
||
isLoadingItems += Plasmoid.configuration.BIfeaturesupdate
|
||
//featuresBlocked = true
|
||
superWorker.sendMessage({ "action": "post_feature", "name": model.name, "value": !model.value })
|
||
}
|
||
}
|
||
}
|
||
//onClicked: {
|
||
//}
|
||
}
|
||
}
|
||
Item {
|
||
width: featuresListContainer.width
|
||
height: Kirigami.Units.smallSpacing/2
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Placeholder for other tabs
|
||
// PlasmaExtras.PlaceholderMessage { text: "Chairy Support" } // да в пизду крч нахуй надо
|
||
}
|
||
}
|
||
}
|
||
}
|