kde-widget/com.umorist47.meowrelaygui/contents/ui/main.qml
2026-03-08 03:16:28 +03:00

1404 lines
64 KiB
QML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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" } // да в пизду крч нахуй надо
}
}
}
}