1.0
This commit is contained in:
commit
5680d76e8b
8 changed files with 1964 additions and 0 deletions
10
com.umorist47.meowrelaygui/contents/config/config.qml
Normal file
10
com.umorist47.meowrelaygui/contents/config/config.qml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import QtQuick
|
||||
import org.kde.plasma.configuration
|
||||
|
||||
ConfigModel {
|
||||
ConfigCategory {
|
||||
name: "General"
|
||||
icon: Qt.resolvedUrl("../images/dogfood.svg")
|
||||
source: "config/General.qml"
|
||||
}
|
||||
}
|
||||
81
com.umorist47.meowrelaygui/contents/config/main.xml
Normal file
81
com.umorist47.meowrelaygui/contents/config/main.xml
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
|
||||
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
|
||||
<kcfgfile name=""/>
|
||||
|
||||
<group name="General">
|
||||
<entry name="RoutesAutoUp" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="RoutesUpInt" type="Int">
|
||||
<default>60</default>
|
||||
<min>1</min>
|
||||
<max>1440</max>
|
||||
</entry>
|
||||
<entry name="StatsAutoUp" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="StatsUpInt" type="Int">
|
||||
<default>1</default>
|
||||
<min>1</min>
|
||||
<max>1440</max>
|
||||
</entry>
|
||||
<entry name="ProfileAutoUp" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="ProfileUpInt" type="Int">
|
||||
<default>60</default>
|
||||
<min>1</min>
|
||||
<max>1440</max>
|
||||
</entry>
|
||||
<entry name="AutoPing" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="AutoPingInt" type="Int">
|
||||
<default>5</default>
|
||||
<min>5</min>
|
||||
<max>20</max>
|
||||
</entry>
|
||||
<entry name="OnErrorRefresh" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
|
||||
<entry name="BIinit" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="BIrefresh" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="BIpostcountry" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="BIpostshare" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="BIpostebalka" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="BIdevicesupdate" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="BIfeaturesupdate" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="BIautoupdate" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
|
||||
<entry name="SBdisplay" type="Bool">
|
||||
<default>true</default>
|
||||
</entry>
|
||||
<entry name="ExtraLayout" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="StringLayoutPlacement" type="String">
|
||||
<default>meow_icon iflag_extra provider</default>
|
||||
</entry>
|
||||
</group>
|
||||
|
||||
</kcfg>
|
||||
53
com.umorist47.meowrelaygui/contents/images/dogfood.svg
Normal file
53
com.umorist47.meowrelaygui/contents/images/dogfood.svg
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
id="Layer_1"
|
||||
enable-background="new 0 0 100 100"
|
||||
viewBox="0 0 100 100"
|
||||
version="1.1"
|
||||
sodipodi:docname="paw-symbolic.svg"
|
||||
inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs5" />
|
||||
<sodipodi:namedview
|
||||
id="namedview5"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="7.59"
|
||||
inkscape:cx="47.826087"
|
||||
inkscape:cy="50.658762"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="967"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<path
|
||||
d="m27.6905899 34.1743889c.9704494 1.2511063 2.1611538 2.3145294 3.5135574 3.13797 1.38694.8570976 2.9807472 1.3211365 4.6110115 1.3424988.1997375.0000038.4011307-.0078316.6041718-.0234947 3.8116875-.310936 6.1308937-2.867218 7.5821838-5.6768723 1.6625671-3.5959549 2.2095757-7.6075706 1.5704727-11.517374-.2743645-1.8115234-.7711143-3.5822926-1.4790039-5.2722015-1.1606598-3.0347385-3.2719154-5.6125736-6.0184402-7.3484879-1.3880882-.8690901-2.9876938-1.3414187-4.6252327-1.3657351-.2005539 0-.4051476.0075498-.6137772.0226517-1.7313862.1293359-3.3765545.8068542-4.6968994 1.9342899-2.4161568 2.0348511-3.8965454 5.0749979-4.4730568 8.943635-.2927074 2.1026497-.2779732 4.2366943.0437298 6.335104.4657421 3.4588127 1.8394318 6.7325172 3.9812832 9.4880161z"
|
||||
id="path1"
|
||||
style="fill:#232629;fill-opacity:1" />
|
||||
<path
|
||||
d="m21.4703159 56.1579819c2.0682297-1.9989548 3.3843727-5.1062546 3.3843727-9.2130203.0130386-3.490139-.9501381-6.9143829-2.7807293-9.8859406-1.4948139-2.61026-3.7439079-4.7075806-6.4520836-6.0166683-1.2700024-.5838051-2.6496677-.8907719-4.0473957-.9005203-.3707933.0017223-.7410603.0281696-1.1083336.0791683-1.5750589.2012596-3.0501838.8818207-4.2255216 1.949482-2.1869798 1.8901024-3.5130196 4.9182281-3.7406242 8.935936v1.2963524c.1490023 3.4176598 1.1969333 6.7355309 3.0380213 9.6187515 1.5524182 2.5812492 3.8794909 4.6070518 6.6499987 5.7890625 1.157259.4549332 2.3883362.6931038 3.6317701.7026024.5487375.0028381 1.0961809-.0535583 1.6328115-.1682281 1.5218431-.3270227 2.9169275-1.0864183 4.0177137-2.1869775z"
|
||||
id="path2"
|
||||
style="fill:#232629;fill-opacity:1" />
|
||||
<path
|
||||
d="m63.5806808 38.631382c.2028122.0158882.4042015.0237198.6041641.0234947 1.6302719-.0213699 3.2240829-.4854126 4.6110153-1.3425217 1.352417-.8234253 2.5431213-1.8868484 3.5135574-3.13797 2.1418533-2.7554951 3.5155334-6.0292034 3.9812851-9.4880161.3217926-2.098402.3365173-4.2324619.0437241-6.335104-.5765076-3.8686361-2.0569-6.9087858-4.473053-8.9436369-1.320343-1.1274357-2.9655075-1.8049541-4.6968994-1.9342899-.2084732-.0153394-.413063-.0228896-.6137772-.0226517-1.637558.0243373-3.2371864.4966717-4.6253052 1.3657541-2.7465363 1.7359219-4.8577957 4.3137703-6.0184517 7.3485222-.7078896 1.689909-1.2046356 3.46068-1.4790001 5.2722034-.6390991 3.9098015-.0920944 7.9214191 1.5704689 11.517374 1.4513742 2.8096239 3.7705957 5.3659021 7.5822717 5.6768419z"
|
||||
id="path3"
|
||||
style="fill:#232629;fill-opacity:1" />
|
||||
<path
|
||||
d="m93.7593765 32.1704826c-1.1753311-1.0676613-2.6504593-1.7482224-4.2255173-1.949482-.3672714-.0509987-.7375412-.077446-1.1083374-.0791683-1.3977203.0097485-2.7773895.3167152-4.0473938.9005203-2.708168 1.3090916-4.9572678 3.4064083-6.4520798 6.0166683-1.8305893 2.9715576-2.7937622 6.3957977-2.7807236 9.8859367 0 4.1067696 1.3161469 7.2140617 3.3843765 9.2130165 1.1007843 1.1005592 2.4958649 1.8599472 4.0177002 2.1869774.5366364.1146698 1.0840836.1710663 1.6328125.1682281 1.2434387-.0094986 2.4745102-.2476692 3.6317749-.7026024 2.7705078-1.1820107 5.09758-3.2078133 6.6500015-5.7890625 1.8410797-2.8832207 2.8889999-6.201088 3.0380096-9.6187439v-1.2963524c-.2276075-4.0177076-1.5536421-7.0458334-3.7406233-8.9359358z"
|
||||
id="path4"
|
||||
style="fill:#232629;fill-opacity:1" />
|
||||
<path
|
||||
d="m83.0666504 82.109375c-.9733047 3.7200546-3.4400253 6.8533554-6.8266602 8.6666718-1.8133163 1.0533829-3.8666153 1.6666641-5.9599609 1.7732697h-1.5733185c-1.1333847-.0665665-2.2666855-.2265625-3.3867188-.4664688-5.2799492-1.1201172-9.7999687-3.1868515-16.119957-3.1868515-2.2666817.0400391-4.5066719.3867188-6.6800117 1.0400391-2.0400391.5467148-4.0133476 1.1201172-6.079998 1.6266327-2.2133751.6000977-4.4800587.9200821-6.7733536.9467773-2.1466465.0265274-4.2666836-.533371-6.1333008-1.6000977-1.5866699-.9199219-2.9867344-2.1598358-4.0933418-3.6266327-1.1733398-1.5598907-2.0266933-3.3466797-2.5066738-5.2399063-.546711-2.2932968-.6133614-4.6800156-.1866856-7.0133438.7466621-3.8666992 2.4799805-7.4534531 5.0533028-10.4401016.5866699-.7200546 1.1733398-1.3999062 1.8133965-2.0533867.6399727-.6399765 1.3465977-1.2265625 2.0266094-1.8531914 1.333334-1.2400703 2.5866699-2.5734062 3.746664-3.9866524 2.2800293-2.8001328 4.3333321-5.9733086 6.546711-8.9733086 2.1599922-2.9200821 4.4799805-5.9467773 7.7866211-7.6666641 1.7466621-.9334335 3.706707-1.413414 5.6800117-1.4000664.2133789 0 .4400253 0 .6533203.0133476 2.1866875.0533829 4.3466797.5200195 6.3466797 1.3867188 3.546711 1.5999336 5.8266602 4.4666328 7.8933105 7.586586 2.0800781 3.1067696 3.9733887 6.3867188 6.2666855 9.2133789 1.1467285 1.4265938 2.4133301 2.7599297 3.7733536 3.9733086 1.3733673 1.2000313 2.6533203 2.5066719 3.8266602 3.9200859 2.5599747 2.9733047 4.3066406 6.5465469 5.093338 10.3865509.4266816 2.3199844.3600312 4.6933593-.1866836 6.9733047z"
|
||||
id="path5"
|
||||
style="fill:#232629;fill-opacity:1" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.8 KiB |
163
com.umorist47.meowrelaygui/contents/ui/.unused.qml
Normal file
163
com.umorist47.meowrelaygui/contents/ui/.unused.qml
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
// functions from main.qml --> reworked
|
||||
// GET routes
|
||||
function fetchRoutes() {
|
||||
isLoading = true;
|
||||
routeModel.clear();
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "http://10.7.0.1:7777/routes");
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
isLoading = false;
|
||||
if (xhr.status === 200) {
|
||||
var response = JSON.parse(xhr.responseText);
|
||||
for (var i = 0; i < response.length; i++) {
|
||||
routeModel.append(response[i]);
|
||||
}
|
||||
} else {
|
||||
console.error("Failed to fetch routes:", xhr.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
// GET profile
|
||||
function fetchProfile() {
|
||||
//isLoading = true;
|
||||
profileModel.clear();
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "http://10.7.0.1:7777/me/profile");
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
//isLoading = false;
|
||||
if (xhr.status === 200) {
|
||||
profileData = JSON.parse(xhr.responseText);
|
||||
//for (var i = 0; i < response.length; i++) {
|
||||
// profileModel.append(response[i]);
|
||||
//}
|
||||
} else {
|
||||
console.error("Failed to fetch profile:", xhr.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
// GET stats
|
||||
function fetchStats() {
|
||||
//isLoading = true;
|
||||
statsModel.clear();
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "http://10.7.0.1:7777/stats");
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
//isLoading = false;
|
||||
if (xhr.status === 200) {
|
||||
statsData = JSON.parse(xhr.responseText);
|
||||
//for (var i = 0; i < response.length; i++) {
|
||||
// profileModel.append(response[i]);
|
||||
//}
|
||||
} else {
|
||||
console.error("Failed to fetch profile:", xhr.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
// POST select country
|
||||
function selectCountry(code, provider) {
|
||||
isLoading = true;
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "http://10.7.0.1:7777/me/country");
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
|
||||
var data = JSON.stringify({
|
||||
"countryCode": code,
|
||||
"provider": provider
|
||||
});
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
isLoading = false;
|
||||
if (xhr.status === 200) {
|
||||
console.log("Success: Changed to " + code);
|
||||
} else {
|
||||
console.error("POST failed:", xhr.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send(data);
|
||||
}
|
||||
|
||||
// POST switch share
|
||||
function switchShare(bool) {
|
||||
//isLoading = true;
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "http://10.7.0.1:7777/me/profile");
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
|
||||
var data = JSON.stringify({
|
||||
"shareTraffic": bool
|
||||
});
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
//isLoading = false;
|
||||
if (xhr.status === 200) {
|
||||
console.log("Success: Share changed to " + bool);
|
||||
} else {
|
||||
console.error("POST failed:", xhr.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send(data);
|
||||
}
|
||||
|
||||
// POST switch ebalka
|
||||
function switchEbalka(bool, ip) {
|
||||
//isLoading = true;
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "http://10.7.0.1:7777/me/ebalka");
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
|
||||
var data = JSON.stringify({
|
||||
"ebalka": bool,
|
||||
"ip": ip
|
||||
});
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
//isLoading = false;
|
||||
if (xhr.status === 200) {
|
||||
console.log("Success: Ebalka for " + ip + " changed to " + bool);
|
||||
} else {
|
||||
console.error("POST failed:", xhr.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send(data);
|
||||
}
|
||||
|
||||
// не смотрите сюда
|
||||
function getFlag($code) {
|
||||
if ($code == 'US') return '🇺🇸';
|
||||
if ($code == 'FI') return '🇫🇮';
|
||||
if ($code == 'EE') return '🇪🇪';
|
||||
if ($code == 'DE') return '🇩🇪';
|
||||
if ($code == 'AM') return '🇦🇲';
|
||||
if ($code == 'AD') return '🇦🇩';
|
||||
if ($code == 'GB') return '🇬🇧';
|
||||
if ($code == 'MC') return '🇲🇨';
|
||||
if ($code == 'HK') return '🇭🇰';
|
||||
if ($code == 'ES') return '🇪🇸';
|
||||
if ($code == 'RU') return '🇷🇺';
|
||||
if ($code == 'CH') return '🇨🇭';
|
||||
return '❔';
|
||||
}
|
||||
189
com.umorist47.meowrelaygui/contents/ui/config/General.qml
Normal file
189
com.umorist47.meowrelaygui/contents/ui/config/General.qml
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kcmutils as KCM
|
||||
import org.kde.plasma.components as PlasmaComponents
|
||||
|
||||
KCM.SimpleKCM {
|
||||
id: generalConfig
|
||||
|
||||
property alias cfg_RoutesAutoUp: enableRoutesUpdate.checked
|
||||
property alias cfg_RoutesUpInt: routesUpdateInterval.value
|
||||
property alias cfg_StatsAutoUp: enableStatsUpdate.checked
|
||||
property alias cfg_StatsUpInt: statsUpdateInterval.value
|
||||
property alias cfg_ProfileAutoUp: enableProfileUpdate.checked
|
||||
property alias cfg_ProfileUpInt: profileUpdateInterval.value
|
||||
|
||||
property alias cfg_AutoPing: enablePing.checked
|
||||
property alias cfg_AutoPingInt: pingInterval.value
|
||||
property alias cfg_OnErrorRefresh: enableOnErrorRefresh.checked
|
||||
|
||||
property alias cfg_BIinit: showOnInitBI.checked
|
||||
property alias cfg_BIrefresh: showRefreshBI.checked
|
||||
property alias cfg_BIpostcountry: showPostCountryBI.checked
|
||||
property alias cfg_BIpostshare: showSwitchShareBI.checked
|
||||
property alias cfg_BIpostebalka: showSwitchEbalkaBI.checked
|
||||
property alias cfg_BIdevicesupdate: showDevicesActionsBI.checked
|
||||
property alias cfg_BIfeaturesupdate: showFeaturesActionsBI.checked
|
||||
property alias cfg_BIautoupdate: showAutoUpdateBI.checked
|
||||
|
||||
property alias cfg_SBdisplay: showSB.checked
|
||||
property alias cfg_ExtraLayout: showExtra.checked
|
||||
property alias cfg_StringLayoutPlacement: extraInput.text
|
||||
|
||||
Kirigami.FormLayout {
|
||||
id: form
|
||||
|
||||
Kirigami.Separator {
|
||||
Kirigami.FormData.isSection: true
|
||||
Kirigami.FormData.label: i18n("AutoUpdate content")
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Kirigami.FormData.label: i18n("Routes")
|
||||
CheckBox {
|
||||
id: enableRoutesUpdate
|
||||
}
|
||||
SpinBox {
|
||||
id: routesUpdateInterval
|
||||
enabled: enableRoutesUpdate.checked
|
||||
from: 1
|
||||
to: 1440
|
||||
textFromValue: function(text) { return text + "m"; }
|
||||
valueFromText: function(value) { return parseInt(value); }
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
Kirigami.FormData.label: i18n("Stats")
|
||||
CheckBox {
|
||||
id: enableStatsUpdate
|
||||
}
|
||||
SpinBox {
|
||||
id: statsUpdateInterval
|
||||
enabled: enableStatsUpdate.checked
|
||||
from: 1
|
||||
to: 1440
|
||||
textFromValue: function(text) { return text + "m"; }
|
||||
valueFromText: function(value) { return parseInt(value); }
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
Kirigami.FormData.label: i18n("Profile")
|
||||
CheckBox {
|
||||
id: enableProfileUpdate
|
||||
}
|
||||
SpinBox {
|
||||
id: profileUpdateInterval
|
||||
enabled: enableProfileUpdate.checked
|
||||
from: 1
|
||||
to: 1440
|
||||
textFromValue: function(text) { return text + "m"; }
|
||||
valueFromText: function(value) { return parseInt(value); }
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
Kirigami.FormData.label: i18n("Ping")
|
||||
CheckBox {
|
||||
id: enablePing
|
||||
}
|
||||
SpinBox {
|
||||
id: pingInterval
|
||||
enabled: enablePing.checked
|
||||
from: 5
|
||||
to: 20
|
||||
textFromValue: function(text) { return text + "s"; }
|
||||
valueFromText: function(value) { return parseInt(value); }
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
Kirigami.FormData.label: i18n("AutoRefresh on error")
|
||||
CheckBox {
|
||||
id: enableOnErrorRefresh
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.Separator {
|
||||
Kirigami.FormData.isSection: true
|
||||
Kirigami.FormData.label: i18n("Busy indicator")
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
Kirigami.FormData.label: i18n("Show Busy indicator on actions:")
|
||||
id: showOnInitBI
|
||||
text: i18n("Plasmoid Init")
|
||||
}
|
||||
CheckBox {
|
||||
id: showRefreshBI
|
||||
text: i18n("Refresh button")
|
||||
}
|
||||
CheckBox {
|
||||
id: showPostCountryBI
|
||||
text: i18n("Select country")
|
||||
}
|
||||
CheckBox {
|
||||
id: showSwitchShareBI
|
||||
text: i18n("Switch Share")
|
||||
}
|
||||
CheckBox {
|
||||
id: showSwitchEbalkaBI
|
||||
text: i18n("Switch 80% loss")
|
||||
}
|
||||
CheckBox {
|
||||
id: showDevicesActionsBI
|
||||
text: i18n("Devices actions")
|
||||
}
|
||||
CheckBox {
|
||||
id: showFeaturesActionsBI
|
||||
text: i18n("Features actions")
|
||||
}
|
||||
CheckBox {
|
||||
id: showAutoUpdateBI
|
||||
text: i18n("AutoUpdate actions")
|
||||
}
|
||||
|
||||
Kirigami.Separator {
|
||||
Kirigami.FormData.isSection: true
|
||||
Kirigami.FormData.label: i18n("Extra")
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Kirigami.FormData.label: i18n("Show scrollbars")
|
||||
CheckBox {
|
||||
id: showSB
|
||||
}
|
||||
Kirigami.ContextualHelpButton {
|
||||
toolTipText: i18n(
|
||||
"If true, scrollbars will be shown as needed"
|
||||
)
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
Kirigami.FormData.label: i18n("CompactRepresentation extra data display")
|
||||
CheckBox {
|
||||
id: showExtra
|
||||
}
|
||||
TextField {
|
||||
id: extraInput
|
||||
enabled: showExtra.checked
|
||||
placeholderText: "meow_icon iflag_extra provider ..."
|
||||
//bottomPadding: Kirigami.Units.gridUnit
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
}
|
||||
PlasmaComponents.Label {
|
||||
text: (
|
||||
"meow_icon - plasmoid icon\n" +
|
||||
"user - your username\n" +
|
||||
"current_device - current device name\n" +
|
||||
"current - current country code (US, FI etc.)\n" +
|
||||
"provider - vpn provider (NORD, WARP etc.)\n" +
|
||||
"ip - current device ip (MeowRelay local)\n" +
|
||||
"iflag - current country flag\n" +
|
||||
"iflag_extra - current country flag + country code (joined)\n" +
|
||||
"any variable from main.qml (root section)"
|
||||
)
|
||||
opacity: 0.7
|
||||
}
|
||||
}
|
||||
}
|
||||
1091
com.umorist47.meowrelaygui/contents/ui/main.qml
Normal file
1091
com.umorist47.meowrelaygui/contents/ui/main.qml
Normal file
File diff suppressed because it is too large
Load diff
356
com.umorist47.meowrelaygui/contents/ui/worker.mjs
Normal file
356
com.umorist47.meowrelaygui/contents/ui/worker.mjs
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
// чисто в теории это должно помочь долгой загрузке пакетов (так гемини сказал)
|
||||
// на деле же хуй знает ибо там иногда хендшейк слетает и он просто заного его шлет
|
||||
const xhrPool = [];
|
||||
const MAX_POOL_SIZE = 6; // Qt's typical max concurrent connections
|
||||
|
||||
function getXhr() {
|
||||
// Look for an idle object
|
||||
for (let i = 0; i < xhrPool.length; i++) {
|
||||
if (xhrPool[i].readyState === 0 || xhrPool[i].readyState === 4) {
|
||||
return xhrPool[i];
|
||||
}
|
||||
}
|
||||
// If none idle and we have room, make a new one
|
||||
if (xhrPool.length < MAX_POOL_SIZE) {
|
||||
let newXhr = new XMLHttpRequest();
|
||||
xhrPool.push(newXhr);
|
||||
return newXhr;
|
||||
}
|
||||
// If all busy, return null (you should queue the request)
|
||||
return null;
|
||||
}
|
||||
|
||||
// KeepAlive ping
|
||||
function keepAlivePing() {
|
||||
let xhr = getXhr();
|
||||
|
||||
if (!xhr) {
|
||||
console.log("Pool full, retrying...");
|
||||
setTimeout(() => keepAlivePing(), 100);
|
||||
return;
|
||||
}
|
||||
xhr.open("HEAD", "http://10.7.0.1:7777/me/profile");
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
//isLoading = false;
|
||||
if (xhr.status === 200) {
|
||||
//console.log("ping pong")
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
// GET routes
|
||||
function fetchRoutes() {
|
||||
//isLoading = true;
|
||||
//routeModel.clear();
|
||||
|
||||
let xhr = getXhr();
|
||||
|
||||
if (!xhr) {
|
||||
console.log("Pool full, retrying...");
|
||||
setTimeout(() => fetchRoutes(), 100);
|
||||
return;
|
||||
}
|
||||
xhr.open("GET", "http://10.7.0.1:7777/routes");
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
//isLoading = false;
|
||||
if (xhr.status === 200) {
|
||||
let response = JSON.parse(xhr.responseText);
|
||||
WorkerScript.sendMessage({ "action": "fetch_routes", "data": response });
|
||||
//for (var i = 0; i < response.length; i++) {
|
||||
// routeModel.append(response[i]);
|
||||
//}
|
||||
} else {
|
||||
WorkerScript.sendMessage({ "action": "fetch_routes", "data": [{"code":"ERR","name":"Error, please try again :<","provider":xhr.status}] });
|
||||
console.error("Failed to fetch routes:", xhr.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
// GET profile
|
||||
function fetchProfile() {
|
||||
//isLoading = true;
|
||||
//profileModel.clear();
|
||||
|
||||
let xhr = getXhr();
|
||||
|
||||
if (!xhr) {
|
||||
console.log("Pool full, retrying...");
|
||||
setTimeout(() => fetchProfile(), 100);
|
||||
return;
|
||||
}
|
||||
xhr.open("GET", "http://10.7.0.1:7777/me/profile");
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
//isLoading = false;
|
||||
if (xhr.status === 200) {
|
||||
let response = JSON.parse(xhr.responseText);
|
||||
WorkerScript.sendMessage({ "action": "fetch_profile", "data": response });
|
||||
//for (var i = 0; i < response.length; i++) {
|
||||
// profileModel.append(response[i]);
|
||||
//}
|
||||
} else {
|
||||
WorkerScript.sendMessage({ "action": "fetch_profile", "data": {"provider":xhr.status, "current_device":"error"} });
|
||||
console.error("Failed to fetch profile:", xhr.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
// GET stats
|
||||
function fetchStats() {
|
||||
//isLoading = true;
|
||||
//statsModel.clear();
|
||||
|
||||
let xhr = getXhr();
|
||||
|
||||
if (!xhr) {
|
||||
console.log("Pool full, retrying...");
|
||||
setTimeout(() => fetchStats(), 100);
|
||||
return;
|
||||
}
|
||||
xhr.open("GET", "http://10.7.0.1:7777/stats");
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
//isLoading = false;
|
||||
if (xhr.status === 200) {
|
||||
let response = JSON.parse(xhr.responseText);
|
||||
WorkerScript.sendMessage({ "action": "fetch_stats", "data": response });
|
||||
//for (var i = 0; i < response.length; i++) {
|
||||
// profileModel.append(response[i]);
|
||||
//}
|
||||
} else {
|
||||
WorkerScript.sendMessage({ "action": "fetch_stats", "data": {} });
|
||||
console.error("Failed to fetch profile:", xhr.status);
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
// POST select country
|
||||
function selectCountry(code, provider) {
|
||||
//isLoading = true;
|
||||
|
||||
let xhr = getXhr();
|
||||
|
||||
if (!xhr) {
|
||||
console.log("Pool full, retrying...");
|
||||
setTimeout(() => selectCountry(code, provider), 100);
|
||||
return;
|
||||
}
|
||||
xhr.open("POST", "http://10.7.0.1:7777/me/country");
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
|
||||
var data = JSON.stringify({
|
||||
"countryCode": code,
|
||||
"provider": provider
|
||||
});
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
//isLoading = false;
|
||||
if (xhr.status === 200) {
|
||||
console.log("Success: Changed to " + code);
|
||||
WorkerScript.sendMessage({ "action": "post_country", "status": xhr.status});
|
||||
} else {
|
||||
console.error("POST failed:", xhr.status);
|
||||
WorkerScript.sendMessage({ "action": "post_country", "status": xhr.status});
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send(data);
|
||||
}
|
||||
|
||||
// POST switch share
|
||||
function switchShare(bool) {
|
||||
//isLoading = true;
|
||||
|
||||
let xhr = getXhr();
|
||||
|
||||
if (!xhr) {
|
||||
console.log("Pool full, retrying...");
|
||||
setTimeout(() => switchShare(bool), 100);
|
||||
return;
|
||||
}
|
||||
xhr.open("POST", "http://10.7.0.1:7777/me/profile");
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
|
||||
var data = JSON.stringify({
|
||||
"shareTraffic": bool
|
||||
});
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
//isLoading = false;
|
||||
if (xhr.status === 200) {
|
||||
console.log("Success: Share changed to " + bool);
|
||||
WorkerScript.sendMessage({ "action": "post_share", "status": xhr.status});
|
||||
} else {
|
||||
console.error("POST failed:", xhr.status);
|
||||
WorkerScript.sendMessage({ "action": "post_share", "status": xhr.status});
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send(data);
|
||||
}
|
||||
|
||||
// POST switch ebalka
|
||||
function switchEbalka(bool, ip) {
|
||||
//isLoading = true;
|
||||
|
||||
let xhr = getXhr();
|
||||
|
||||
if (!xhr) {
|
||||
console.log("Pool full, retrying...");
|
||||
setTimeout(() => switchEbalka(bool, ip), 100);
|
||||
return;
|
||||
}
|
||||
xhr.open("POST", "http://10.7.0.1:7777/me/ebalka");
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
|
||||
var data = JSON.stringify({
|
||||
"ebalka": bool,
|
||||
"ip": ip
|
||||
});
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
//isLoading = false;
|
||||
if (xhr.status === 200) {
|
||||
console.log("Success: Ebalka for " + ip + " changed to " + bool);
|
||||
WorkerScript.sendMessage({ "action": "post_ebalka", "status": xhr.status, "ip": ip});
|
||||
} else {
|
||||
console.error("POST failed:", xhr.status);
|
||||
WorkerScript.sendMessage({ "action": "post_ebalka", "status": xhr.status, "ip": ip});
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send(data);
|
||||
}
|
||||
|
||||
// POST switch ebalka
|
||||
function renameDevice(ip, name) {
|
||||
//isLoading = true;
|
||||
|
||||
let xhr = getXhr();
|
||||
|
||||
if (!xhr) {
|
||||
console.log("Pool full, retrying...");
|
||||
setTimeout(() => renameDevice(ip, name), 100);
|
||||
return;
|
||||
}
|
||||
xhr.open("POST", "http://10.7.0.1:7777/me/device");
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
|
||||
var data = JSON.stringify({
|
||||
"ip": ip,
|
||||
"name": name
|
||||
});
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
//isLoading = false;
|
||||
if (xhr.status === 200) {
|
||||
console.log("Success: Name for " + ip + " changed to " + name);
|
||||
WorkerScript.sendMessage({ "action": "post_name", "status": xhr.status, "ip": ip});
|
||||
} else {
|
||||
console.error("POST failed:", xhr.status);
|
||||
WorkerScript.sendMessage({ "action": "post_name", "status": xhr.status, "ip": ip});
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send(data);
|
||||
}
|
||||
|
||||
// POST feature switch
|
||||
function switchFeature(name, value) {
|
||||
//isLoading = true;
|
||||
|
||||
let xhr = getXhr();
|
||||
|
||||
if (!xhr) {
|
||||
console.log("Pool full, retrying...");
|
||||
setTimeout(() => switchFeature(name, value), 100);
|
||||
return;
|
||||
}
|
||||
xhr.open("POST", "http://10.7.0.1:7777/me/feature");
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
|
||||
var data = JSON.stringify({
|
||||
"name": name,
|
||||
"value": value
|
||||
});
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
//isLoading = false;
|
||||
if (xhr.status === 200) {
|
||||
console.log("Success: Feature " + name + " changed to " + value);
|
||||
WorkerScript.sendMessage({ "action": "post_feature" });
|
||||
} else {
|
||||
console.error("POST failed:", xhr.status);
|
||||
WorkerScript.sendMessage({ "action": "post_feature" });
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send(data);
|
||||
}
|
||||
|
||||
// POST connect by server id
|
||||
function connectById(iface) {
|
||||
//isLoading = true;
|
||||
|
||||
let xhr = getXhr();
|
||||
|
||||
if (!xhr) {
|
||||
console.log("Pool full, retrying...");
|
||||
setTimeout(() => connectById(iface), 100);
|
||||
return;
|
||||
}
|
||||
xhr.open("POST", "http://10.7.0.1:7777/me/connect_by_id");
|
||||
xhr.setRequestHeader("Content-Type", "application/json");
|
||||
|
||||
var data = JSON.stringify({
|
||||
"iface": iface
|
||||
});
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
//isLoading = false;
|
||||
if (xhr.status === 200) {
|
||||
console.log("Success: Changed to " + iface);
|
||||
WorkerScript.sendMessage({ "action": "post_idconnect", "status": xhr.status});
|
||||
} else {
|
||||
console.error("POST failed:", xhr.status);
|
||||
WorkerScript.sendMessage({ "action": "post_idconnect", "status": xhr.status});
|
||||
}
|
||||
}
|
||||
}
|
||||
xhr.send(data);
|
||||
}
|
||||
|
||||
WorkerScript.onMessage = function(message) {
|
||||
const actions = {
|
||||
"fetch_routes": () => fetchRoutes(message),
|
||||
"fetch_stats": () => fetchStats(message),
|
||||
"fetch_profile": () => fetchProfile(message),
|
||||
"post_country": () => selectCountry(message.code, message.provider),
|
||||
"post_share": () => switchShare(message.bool),
|
||||
"post_ebalka": () => switchEbalka(message.bool, message.ip),
|
||||
"post_name": () => renameDevice(message.ip, message.name),
|
||||
"post_feature": () => switchFeature(message.name, message.value),
|
||||
"post_idconnect": () => connectById(message.iface),
|
||||
"ping": () => keepAlivePing(message)
|
||||
};
|
||||
|
||||
if (actions[message.action]) {
|
||||
actions[message.action]();
|
||||
}
|
||||
}
|
||||
21
com.umorist47.meowrelaygui/metadata.json
Normal file
21
com.umorist47.meowrelaygui/metadata.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"KPackageStructure": "Plasma/Applet",
|
||||
"KPlugin": {
|
||||
"Authors": [
|
||||
{
|
||||
"Email": "me@umorist47.ru",
|
||||
"Name": "Umorist Kekovich"
|
||||
}
|
||||
],
|
||||
"Category": "System",
|
||||
"Description": "MeowRelay configurator plasmoid.",
|
||||
"EnabledByDefault": true,
|
||||
"Icon": "preferences-system-network-proxy",
|
||||
"Id": "com.umorist47.meowrelaygui",
|
||||
"Name": "MeowRelay",
|
||||
"Version": "1.0",
|
||||
"Website": "",
|
||||
"License": "GPL3"
|
||||
},
|
||||
"X-Plasma-API-Minimum-Version": "6.0"
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue