├── .editorconfig ├── .gitignore ├── CMakeLists.txt ├── ChangeLog ├── LICENSE ├── README.md ├── install.sh ├── netspeed-widget.png ├── package ├── contents │ ├── code │ │ └── utils.js │ ├── config │ │ ├── config.qml │ │ └── main.xml │ └── ui │ │ ├── CompactRepresentation.qml │ │ ├── Launcher.qml │ │ ├── config │ │ ├── AppMenuDialog.qml │ │ ├── AppPicker.qml │ │ ├── ColorPicker.qml │ │ ├── ConfigAdvanced.qml │ │ └── ConfigGeneral.qml │ │ └── main.qml └── metadata.json ├── release.sh └── run.sh /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_size = 4 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.qmlc 2 | *.plasmoid 3 | build 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) 2 | project(plasma-applet-netspeed-widget) 3 | 4 | find_package(ECM 0.0.11 REQUIRED NO_MODULE) 5 | set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) 6 | 7 | set(QT_MAJOR_VERSION 6) 8 | 9 | include(KDEInstallDirs) 10 | 11 | find_package(Plasma REQUIRED) 12 | 13 | plasma_install_package(package org.kde.netspeedWidget) 14 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 3.1 (2024.03.10): 2 | Fix tooltip area 3 | 4 | 3.0 (2024.03.10): 5 | Port to KF6 (big thanks to github.com/jas0n098) 6 | 7 | 2.0 (2023.08.04): 8 | Use "/proc/net/dev" as data source 9 | Add "show low speeds" config option 10 | Limit values to three pre-decimal point digits 11 | 12 | 1.9 (2020.09.03): 13 | Use native text rendering 14 | Make quicklaunch an optional dependency 15 | 16 | 1.8 (2019.10.06): 17 | Fix launching application on KF5 5.61.0 and above 18 | 19 | 1.7 (2019.05.17): 20 | Add setting to overwrite automatic layout 21 | 22 | 1.6 (2019.01.31): 23 | Improve margins and disable clipping 24 | 25 | 1.5 (2018.08.06): 26 | Add config option to change upload and download display order 27 | 28 | 1.4 (2017.07.08): 29 | Add optional interfaces whitelist 30 | 31 | 1.3 (2016.03.03): 32 | Show combined network speed for all devices 33 | Display proper (long) speed units 34 | Show download and upload speed separately config option 35 | Launch user defined application when clicked 36 | 37 | 1.2 (2016.02.09): 38 | Layout fixes 39 | Shortened speed units config option 40 | 41 | 1.1 (2016.01.18): 42 | Layout fixes 43 | Font size config option 44 | 45 | 1.0 (2016.01.16): 46 | First release 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # plasma-applet-netspeed-widget 2 | 3 | Plasma 5 and 6 widget that displays the currently used network bandwidth. 4 | 5 | ![Screen shot of plasma-applet-netspeed-widget](netspeed-widget.png) 6 | 7 | Dependencies: 8 | 9 | * awk 10 | 11 | Optional dependencies: 12 | 13 | * plasma-addons (may be called plasma5-addons, kdeplasma-addons or similar - used to launch a user defined application when the applet is clicked) 14 | 15 | ## Installation 16 | 17 | ### From openDesktop.org 18 | 19 | 1. Go to [https://www.opendesktop.org/p/998895/](https://www.opendesktop.org/p/998895/) for the Plasma 5 version, or [https://www.opendesktop.org/p/2136505/](https://www.opendesktop.org/p/2136505/) for the Plasma 6 version. 20 | 2. Click on the `Files` tab. 21 | 3. Click the `Install` button. 22 | 4. Make sure the package `awk` is installed. 23 | 24 | ### From within the Plasma workspace 25 | 26 | 1. If your widgets are locked, right-click the desktop and select `Unlock Widgets`. 27 | 2. Right-click the desktop and select `Add Widgets...`. 28 | 3. Click the `Get new widgets` button in the Widget Explorer that just opened. 29 | 4. Type `Netspeed Widget` into the search field. 30 | 5. Click the `Install` button next to "Netspeed Widget". 31 | 6. Make sure the package `awk` is installed. 32 | 33 | ### From source 34 | 35 | ```bash 36 | git clone https://github.com/dfaust/plasma-applet-netspeed-widget 37 | cd plasma-applet-netspeed-widget 38 | ./install.sh 39 | ``` 40 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | mkdir --parents --verbose ~/.local/share/plasma/plasmoids/org.kde.netspeedWidget 4 | cp --recursive --update --verbose ./package/* $_ 5 | -------------------------------------------------------------------------------- /netspeed-widget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dfaust/plasma-applet-netspeed-widget/5f54d7515c8770a7e81f1edd6bab429ff0f5db21/netspeed-widget.png -------------------------------------------------------------------------------- /package/contents/code/utils.js: -------------------------------------------------------------------------------- 1 | const NET_DATA_SOURCE = 2 | "awk -v OFS=, 'NR > 2 { print substr($1, 1, length($1)-1), $2, $10 }' /proc/net/dev"; 3 | 4 | function parseTransferData(data) { 5 | const transferData = {}; 6 | 7 | for (const line of data.trim("\n").split("\n")) { 8 | const [name, rx, tx] = line.split(","); 9 | 10 | if (name === "lo") { 11 | continue; 12 | } 13 | 14 | transferData[name] = { rx, tx }; 15 | } 16 | 17 | return transferData; 18 | } 19 | 20 | function calcSpeedData(prevTransferData, nextTransferData, duration) { 21 | const speedData = {}; 22 | 23 | for (const key in nextTransferData) { 24 | if (prevTransferData && key in prevTransferData) { 25 | const prev = prevTransferData[key]; 26 | const next = nextTransferData[key]; 27 | speedData[key] = { 28 | down: ((next.rx - prev.rx) * 1000) / duration, 29 | up: ((next.tx - prev.tx) * 1000) / duration, 30 | downTotal: nextTransferData[key].rx, 31 | upTotal: nextTransferData[key].tx, 32 | }; 33 | } 34 | } 35 | 36 | return speedData; 37 | } 38 | -------------------------------------------------------------------------------- /package/contents/config/config.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.2 2 | import org.kde.plasma.configuration 2.0 3 | 4 | ConfigModel { 5 | ConfigCategory { 6 | name: i18n('General') 7 | icon: 'preferences-desktop-color' 8 | source: 'config/ConfigGeneral.qml' 9 | } 10 | ConfigCategory { 11 | name: i18n('Advanced') 12 | icon: 'preferences-desktop-launch-feedback' 13 | source: 'config/ConfigAdvanced.qml' 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /package/contents/config/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | true 11 | 12 | 13 | false 14 | 15 | 16 | auto 17 | 18 | 19 | false 20 | 21 | 22 | true 23 | 24 | 25 | 26 | true 27 | 28 | 29 | 30 | bytes 31 | 32 | 33 | 34 | false 35 | 36 | 37 | 38 | 100 39 | 40 | 41 | 42 | 1.0 43 | 44 | 45 | 46 | false 47 | 48 | 49 | #000000 50 | 51 | 52 | #800080 53 | 54 | 55 | #FF0000 56 | 57 | 58 | #FF8000 59 | 60 | 61 | 62 | 63 | 64 | false 65 | 66 | 67 | 68 | 69 | 70 | false 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /package/contents/ui/CompactRepresentation.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Daniel Faust 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | import QtQuick 18 | import QtQuick.Layouts 19 | import org.kde.plasma.core as PlasmaCore 20 | import org.kde.plasma.plasma5support as Plasma5Support 21 | import org.kde.kirigami as Kirigami 22 | 23 | Item { 24 | anchors.fill: parent 25 | 26 | property double marginFactor: 0.2 27 | 28 | property double downSpeed: { 29 | var speed = 0 30 | for (var key in speedData) { 31 | if (interfacesWhitelistEnabled && interfacesWhitelist.indexOf(key) === -1) { 32 | continue 33 | } 34 | speed += speedData[key].down 35 | } 36 | return speed 37 | } 38 | 39 | property double upSpeed: { 40 | var speed = 0 41 | for (var key in speedData) { 42 | if (interfacesWhitelistEnabled && interfacesWhitelist.indexOf(key) === -1) { 43 | continue 44 | } 45 | speed += speedData[key].up 46 | } 47 | return speed 48 | } 49 | 50 | property bool singleLine: { 51 | if (!showSeparately) { 52 | return true 53 | } 54 | switch (speedLayout) { 55 | case 'rows': return false 56 | case 'columns': return true 57 | default: return height / 2 * fontSizeScale < Kirigami.Theme.smallFont.pixelSize && plasmoid.formFactor != PlasmaCore.Types.Vertical 58 | } 59 | } 60 | 61 | property double marginWidth: speedTextMetrics.font.pixelSize * marginFactor 62 | property double iconWidth: showIcons ? iconTextMetrics.width + marginWidth : 0 63 | property double doubleIconWidth: showIcons ? (doubleIconTextMetrics.width + marginWidth) : 0 64 | property double speedWidth: speedTextMetrics.width + 2*marginWidth 65 | property double unitWidth: showUnits ? unitTextMetrics.width + marginWidth : 0 66 | 67 | property double aspectRatio: { 68 | if (showSeparately) { 69 | if (singleLine) { 70 | return (2*iconWidth + 2*speedWidth + 2*unitWidth + marginWidth) * fontSizeScale / speedTextMetrics.height 71 | } else { 72 | return (iconWidth + speedWidth + unitWidth) * fontSizeScale / (2*speedTextMetrics.height) 73 | } 74 | } else { 75 | return (doubleIconWidth + speedWidth + unitWidth) * fontSizeScale / speedTextMetrics.height 76 | } 77 | } 78 | 79 | property double fontHeightRatio: speedTextMetrics.font.pixelSize / speedTextMetrics.height 80 | 81 | property double offset: { 82 | if (plasmoid.formFactor === PlasmaCore.Types.Vertical) { 83 | return (width - height * aspectRatio) / 2 84 | } else { 85 | return 0 86 | } 87 | } 88 | 89 | Layout.minimumWidth: { 90 | if (plasmoid.formFactor === PlasmaCore.Types.Vertical) { 91 | return 0 92 | } else if (plasmoid.formFactor === PlasmaCore.Types.Horizontal) { 93 | return Math.ceil(height * aspectRatio) 94 | } else { 95 | return Math.ceil(height * aspectRatio) 96 | } 97 | } 98 | Layout.minimumHeight: { 99 | if (plasmoid.formFactor === PlasmaCore.Types.Vertical) { 100 | return Math.ceil(width / aspectRatio * fontSizeScale * fontSizeScale) 101 | } else if (plasmoid.formFactor === PlasmaCore.Types.Horizontal) { 102 | return 0 103 | } else { 104 | return Math.ceil(Kirigami.Theme.smallFont.pixelSize / fontSizeScale) 105 | } 106 | } 107 | 108 | Layout.preferredWidth: Layout.minimumWidth 109 | Layout.preferredHeight: Layout.minimumHeight 110 | 111 | PlasmaCore.ToolTipArea { 112 | anchors.fill: parent 113 | icon: 'network-connect' 114 | mainText: i18n('Network usage') 115 | subText: { 116 | var details = '' 117 | for (var key in speedData) { 118 | if (interfacesWhitelistEnabled && interfacesWhitelist.indexOf(key) === -1) { 119 | continue 120 | } 121 | 122 | if (details != '') { 123 | details += '

' 124 | } 125 | 126 | details += '' + key + '
' 127 | details += 'Downloaded: ' + totalText(speedData[key].downTotal) + ', Uploaded: ' + totalText(speedData[key].upTotal) + '' 128 | } 129 | return details 130 | } 131 | } 132 | 133 | TextMetrics { 134 | id: iconTextMetrics 135 | text: '↓' 136 | font.pixelSize: 64 137 | } 138 | 139 | TextMetrics { 140 | id: doubleIconTextMetrics 141 | text: '↓↑' 142 | font.pixelSize: 64 143 | } 144 | 145 | TextMetrics { 146 | id: speedTextMetrics 147 | text: '1000.0' 148 | font.pixelSize: 64 149 | } 150 | 151 | TextMetrics { 152 | id: unitTextMetrics 153 | text: { 154 | if (speedUnits === 'bits') { 155 | return shortUnits ? 'm' : 'Mb/s' 156 | } else { 157 | return shortUnits ? 'M' : 'MiB/s' 158 | } 159 | } 160 | font.pixelSize: 64 161 | } 162 | 163 | Plasma5Support.DataSource { 164 | id: appsSource 165 | engine: 'apps' 166 | connectedSources: launchApplication 167 | } 168 | 169 | Loader { 170 | id: 'launcher' 171 | source: 'Launcher.qml' 172 | } 173 | 174 | Item { 175 | id: offsetItem 176 | width: offset 177 | height: parent.height 178 | x: 0 179 | y: 0 180 | } 181 | 182 | Text { 183 | id: topIcon 184 | 185 | height: singleLine ? parent.height : parent.height / 2 186 | width: (showSeparately ? 1 : 2) * iconTextMetrics.width / iconTextMetrics.height * height * fontSizeScale 187 | 188 | verticalAlignment: Text.AlignVCenter 189 | anchors.left: offsetItem.right 190 | anchors.leftMargin: font.pixelSize * marginFactor 191 | y: 0 192 | font.pixelSize: height * fontHeightRatio * fontSizeScale 193 | renderType: Text.NativeRendering 194 | 195 | text: showSeparately ? (swapDownUp ? '↑' : '↓') : '↓↑' 196 | color: Kirigami.Theme.textColor 197 | visible: showIcons 198 | } 199 | 200 | Text { 201 | id: topText 202 | 203 | height: singleLine ? parent.height : parent.height / 2 204 | width: speedTextMetrics.width / speedTextMetrics.height * height * fontSizeScale 205 | 206 | horizontalAlignment: Text.AlignRight 207 | verticalAlignment: Text.AlignVCenter 208 | anchors.left: showIcons ? topIcon.right : offsetItem.right 209 | anchors.leftMargin: font.pixelSize * marginFactor 210 | y: 0 211 | font.pixelSize: height * fontHeightRatio * fontSizeScale 212 | renderType: Text.NativeRendering 213 | 214 | text: speedText(showSeparately ? (swapDownUp ? upSpeed : downSpeed) : downSpeed + upSpeed, showLowSpeeds) 215 | color: speedColor(showSeparately ? (swapDownUp ? upSpeed : downSpeed) : downSpeed + upSpeed) 216 | } 217 | 218 | Text { 219 | id: topUnitText 220 | 221 | height: singleLine ? parent.height : parent.height / 2 222 | width: unitTextMetrics.width / unitTextMetrics.height * height * fontSizeScale 223 | 224 | verticalAlignment: Text.AlignVCenter 225 | anchors.left: topText.right 226 | anchors.leftMargin: font.pixelSize * marginFactor 227 | y: 0 228 | font.pixelSize: height * fontHeightRatio * fontSizeScale 229 | renderType: Text.NativeRendering 230 | 231 | text: speedUnit(showSeparately ? (swapDownUp ? upSpeed : downSpeed) : downSpeed + upSpeed) 232 | color: Kirigami.Theme.textColor 233 | visible: showUnits 234 | } 235 | 236 | Text { 237 | id: bottomIcon 238 | 239 | height: singleLine ? parent.height : parent.height / 2 240 | width: iconTextMetrics.width / iconTextMetrics.height * height * fontSizeScale 241 | 242 | verticalAlignment: Text.AlignVCenter 243 | anchors.left: (singleLine && showUnits) ? topUnitText.right : (singleLine ? topText.right : offsetItem.right) 244 | anchors.leftMargin: (singleLine ? 2 : 1) * font.pixelSize * marginFactor 245 | y: singleLine ? 0 : parent.height / 2 246 | font.pixelSize: height * fontHeightRatio * fontSizeScale 247 | renderType: Text.NativeRendering 248 | 249 | text: swapDownUp ? '↓' : '↑' 250 | color: Kirigami.Theme.textColor 251 | visible: showSeparately && showIcons 252 | } 253 | 254 | Text { 255 | id: bottomText 256 | 257 | height: singleLine ? parent.height : parent.height / 2 258 | width: speedTextMetrics.width / speedTextMetrics.height * height * fontSizeScale 259 | 260 | horizontalAlignment: Text.AlignRight 261 | verticalAlignment: Text.AlignVCenter 262 | anchors.left: showIcons ? bottomIcon.right : ((singleLine && showUnits) ? topUnitText.right : (singleLine ? topText.right : offsetItem.right)) 263 | anchors.leftMargin: font.pixelSize * marginFactor 264 | y: singleLine ? 0 : parent.height / 2 265 | font.pixelSize: height * fontHeightRatio * fontSizeScale 266 | renderType: Text.NativeRendering 267 | 268 | text: speedText(swapDownUp ? downSpeed : upSpeed, showLowSpeeds) 269 | color: speedColor(swapDownUp ? downSpeed : upSpeed) 270 | visible: showSeparately 271 | } 272 | 273 | Text { 274 | id: bottomUnitText 275 | 276 | height: singleLine ? parent.height : parent.height / 2 277 | width: unitTextMetrics.width / unitTextMetrics.height * height * fontSizeScale 278 | 279 | verticalAlignment: Text.AlignVCenter 280 | anchors.left: bottomText.right 281 | anchors.leftMargin: font.pixelSize * marginFactor 282 | y: singleLine ? 0 : parent.height / 2 283 | font.pixelSize: height * fontHeightRatio * fontSizeScale 284 | renderType: Text.NativeRendering 285 | 286 | text: speedUnit(swapDownUp ? downSpeed : upSpeed) 287 | color: Kirigami.Theme.textColor 288 | visible: showSeparately && showUnits 289 | } 290 | 291 | MouseArea { 292 | anchors.fill: parent 293 | enabled: launchApplicationEnabled 294 | 295 | onClicked: { 296 | if (launcher.item && appsSource.data[launchApplication]) { 297 | launcher.item.launch("file:" + appsSource.data[launchApplication].entryPath) 298 | } 299 | } 300 | } 301 | 302 | function speedText(value, showLowSpeeds) { 303 | if (speedUnits === 'bits') { 304 | value *= 8 * 1.024 305 | if (value >= 1000 * 1000 * 1000) { 306 | value /= 1000 * 1000 * 1000 307 | } 308 | else if (value >= 1000 * 1000) { 309 | value /= 1000 * 1000 310 | } 311 | else if (value >= 1000) { 312 | value /= 1000 313 | } 314 | else if (!showLowSpeeds) { 315 | value = 0 316 | } 317 | } else { 318 | if (value >= 1000 * 1024 * 1024) { 319 | value /= 1024 * 1024 * 1024 320 | } 321 | else if (value >= 1000 * 1024) { 322 | value /= 1024 * 1024 323 | } 324 | else if (value >= 1000) { 325 | value /= 1024 326 | } 327 | else if (!showLowSpeeds) { 328 | value = 0 329 | } 330 | } 331 | return (Math.round(value * 10) / 10).toFixed(1) 332 | } 333 | 334 | function speedColor(value) { 335 | if (!customColors) { 336 | return Kirigami.Theme.textColor 337 | } 338 | 339 | if (speedUnits === 'bits') { 340 | value *= 8 * 1.024 341 | if (value >= 1000 * 1000 * 1000) { 342 | return gigabyteColor 343 | } 344 | else if (value >= 1000 * 1000) { 345 | return megabyteColor 346 | } 347 | else if (value >= 1000) { 348 | return kilobyteColor 349 | } 350 | else { 351 | return byteColor 352 | } 353 | } else { 354 | if (value >= 1000 * 1024 * 1024) { 355 | return gigabyteColor 356 | } 357 | else if (value >= 1000 * 1024) { 358 | return megabyteColor 359 | } 360 | else if (value >= 1000) { 361 | return kilobyteColor 362 | } 363 | else { 364 | return byteColor 365 | } 366 | } 367 | } 368 | 369 | function speedUnit(value) { 370 | if (speedUnits === 'bits') { 371 | value *= 8 * 1.024 372 | if (value >= 1000 * 1000 * 1000) { 373 | return shortUnits ? 'g' : 'Gb/s' 374 | } 375 | else if (value >= 1000 * 1000) { 376 | return shortUnits ? 'm' : 'Mb/s' 377 | } 378 | else if (value >= 1000) { 379 | return shortUnits ? 'k' : 'Kb/s' 380 | } 381 | else { 382 | return shortUnits ? 'b' : 'b/s' 383 | } 384 | } else { 385 | if (value >= 1000 * 1024 * 1024) { 386 | return shortUnits ? 'G' : 'GiB/s' 387 | } 388 | else if (value >= 1000 * 1024) { 389 | return shortUnits ? 'M' : 'MiB/s' 390 | } 391 | else if (value >= 1000) { 392 | return shortUnits ? 'K' : 'KiB/s' 393 | } 394 | else { 395 | return shortUnits ? 'B' : 'B/s' 396 | } 397 | } 398 | } 399 | 400 | function totalText(value) { 401 | var unit 402 | if (value >= 1024 * 1024 * 1024) { 403 | value /= 1024 * 1024 * 1024 404 | unit = 'GiB' 405 | } 406 | else if (value >= 1024 * 1024) { 407 | value /= 1024 * 1024 408 | unit = 'MiB' 409 | } 410 | else if (value >= 1024) { 411 | value /= 1024 412 | unit = 'KiB' 413 | } 414 | else { 415 | unit = 'B' 416 | } 417 | return (Math.round(value * 10) / 10).toFixed(1) + ' ' + unit 418 | } 419 | } 420 | -------------------------------------------------------------------------------- /package/contents/ui/Launcher.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.5 2 | import org.kde.plasma.private.quicklaunch 1.0 3 | 4 | Item { 5 | Logic { 6 | id: kRun 7 | } 8 | 9 | function launch(url) { 10 | kRun.openUrl(url) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /package/contents/ui/config/AppMenuDialog.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Daniel Faust 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | import QtQuick 18 | import QtQuick.Layouts 19 | import QtQuick.Dialogs 20 | import QtQuick.Controls 21 | import org.kde.kirigami as Kirigami 22 | import org.kde.plasma.plasma5support as Plasma5Support 23 | import org.kde.plasma.components as PlasmaComponents 24 | import org.kde.plasma.extras as PlasmaExtras 25 | 26 | Dialog { 27 | id: appMenuDialog 28 | title: i18n('Choose an application') 29 | standardButtons: Dialog.Cancel 30 | 31 | width: 300 32 | height: 400 33 | 34 | property string selectedMenuId: '' 35 | 36 | Plasma5Support.DataSource { 37 | id: appsSource 38 | engine: 'apps' 39 | connectedSources: sources 40 | } 41 | 42 | ListModel { 43 | id: appsModel 44 | } 45 | 46 | PlasmaComponents.ScrollView { 47 | width: parent.width 48 | height: parent.height 49 | 50 | ListView { 51 | id: apps 52 | anchors.fill: parent 53 | clip: true 54 | 55 | model: appsModel 56 | 57 | highlight: PlasmaExtras.Highlight {} 58 | highlightMoveDuration: 0 59 | highlightResizeDuration: 0 60 | 61 | delegate: Item { 62 | width: apps.width - 20 63 | height: Kirigami.Units.iconSizes.small + 2*Kirigami.Units.smallSpacing 64 | 65 | property bool isHovered: false 66 | 67 | MouseArea { 68 | anchors.fill: parent 69 | 70 | hoverEnabled: true 71 | onEntered: { 72 | apps.currentIndex = index 73 | isHovered = true 74 | } 75 | onExited: { 76 | isHovered = false 77 | } 78 | 79 | onClicked: { 80 | selectedMenuId = desktop 81 | appMenuDialog.accept() 82 | } 83 | 84 | RowLayout { 85 | x: Kirigami.Units.smallSpacing 86 | y: Kirigami.Units.smallSpacing 87 | 88 | Kirigami.Icon { 89 | source: appsSource.data[desktop].iconName 90 | active: isHovered 91 | implicitHeight: Kirigami.Units.iconSizes.small 92 | implicitWidth: implicitHeight 93 | } 94 | 95 | PlasmaComponents.Label { 96 | text: appsSource.data[desktop].name 97 | height: parent.height 98 | verticalAlignment: Text.AlignVCenter 99 | } 100 | } 101 | } 102 | } 103 | 104 | section.property: 'category' 105 | section.delegate: Item { 106 | width: parent.width - 20 107 | height: Kirigami.Units.iconSizes.small + 2*Kirigami.Units.smallSpacing 108 | 109 | Rectangle { 110 | anchors.fill: parent 111 | color: Kirigami.Theme.alternateBackgroundColor 112 | 113 | PlasmaComponents.Label { 114 | x: Kirigami.Units.smallSpacing 115 | y: 0 116 | width: parent.width - 2*Kirigami.Units.smallSpacing 117 | height: parent.height 118 | verticalAlignment: Text.AlignVCenter 119 | text: section 120 | font.bold: true 121 | color: Kirigami.Theme.textColor 122 | } 123 | } 124 | } 125 | 126 | Component.onCompleted: { 127 | listMenuEntries('/') 128 | } 129 | } 130 | } 131 | 132 | function listMenuEntries(menuId) { 133 | for (var i = 0; i < appsSource.data[menuId].entries.length; i++) { 134 | var entry = appsSource.data[menuId].entries[i] 135 | if (/\.desktop$/.test(entry)) { 136 | var category = (menuId == '/') ? '/' : menuId.slice(0, -1); 137 | appsModel.append({desktop: entry, category: category}) 138 | } else if (/\/$/.test(entry) && entry != '.hidden/') { 139 | listMenuEntries(entry) 140 | } 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /package/contents/ui/config/AppPicker.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Daniel Faust 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License or (at your option) version 3 or any later version 8 | * accepted by the membership of KDE e.V. (or its successor approved 9 | * by the membership of KDE e.V.), which shall act as a proxy 10 | * defined in Section 14 of version 3 of the license. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see 19 | */ 20 | import QtQuick 21 | import org.kde.plasma.plasma5support as Plasma5Support 22 | import org.kde.plasma.components as PlasmaComponents 23 | 24 | Item { 25 | id: appPicker 26 | 27 | property string menuId 28 | 29 | width: childrenRect.width 30 | height: childrenRect.height 31 | 32 | onMenuIdChanged: { 33 | if (appsSource.data[menuId]) { 34 | appButton.text = appsSource.data[menuId].name 35 | appButton.iconSource = appsSource.data[menuId].iconName 36 | } else { 37 | appButton.text = i18n('Choose application ...') 38 | } 39 | } 40 | 41 | Plasma5Support.DataSource { 42 | id: appsSource 43 | engine: 'apps' 44 | connectedSources: sources 45 | } 46 | 47 | PlasmaComponents.Button { 48 | id: appButton 49 | text: i18n('Choose application ...') 50 | onClicked: appMenuDialog.open() 51 | } 52 | 53 | AppMenuDialog { 54 | id: appMenuDialog 55 | x: (parent.width - width) / 2 56 | onAccepted: { 57 | menuId = selectedMenuId 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /package/contents/ui/config/ColorPicker.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Martin Yrjölä 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License or (at your option) version 3 or any later version 8 | * accepted by the membership of KDE e.V. (or its successor approved 9 | * by the membership of KDE e.V.), which shall act as a proxy 10 | * defined in Section 14 of version 3 of the license. 11 | * 12 | * This program is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program. If not, see 19 | */ 20 | 21 | import QtQuick 22 | import QtQuick.Layouts 23 | import QtQuick.Dialogs as QtDialogs 24 | import Qt.labs.platform 25 | 26 | Item { 27 | id: colorPicker 28 | 29 | property alias chosenColor: colorDialog.color 30 | 31 | width: childrenRect.width 32 | height: childrenRect.height 33 | Layout.alignment: Qt.AlignVCenter 34 | 35 | Rectangle { 36 | color: colorDialog.color 37 | radius: width / 2 38 | height: 20 39 | width: height 40 | opacity: enabled ? 1 : 0.5 41 | border { 42 | width: mouseArea.containsMouse ? 3 : 1 43 | color: Qt.darker(colorDialog.color, 1.5) 44 | } 45 | 46 | ColorDialog { 47 | id: colorDialog 48 | } 49 | } 50 | 51 | MouseArea { 52 | id: mouseArea 53 | anchors.fill: parent 54 | hoverEnabled: true 55 | onClicked: { 56 | colorDialog.open() 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /package/contents/ui/config/ConfigAdvanced.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Daniel Faust 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | import QtQuick 18 | import QtQuick.Controls 19 | import QtQuick.Layouts 20 | import org.kde.kirigami as Kirigami 21 | import org.kde.plasma.plasma5support as Plasma5Support 22 | import "../../code/utils.js" as Utils 23 | 24 | Kirigami.FormLayout { 25 | property alias cfg_launchApplicationEnabled: launchApplicationEnabled.checked 26 | property alias cfg_launchApplication: launchApplication.menuId 27 | property alias cfg_interfacesWhitelistEnabled: interfacesWhitelistEnabled.checked 28 | property var cfg_interfacesWhitelist: [] 29 | 30 | Loader { 31 | id: 'launcher' 32 | source: '../Launcher.qml' 33 | } 34 | 35 | Plasma5Support.DataSource { 36 | id: dataSource 37 | engine: 'executable' 38 | connectedSources: [Utils.NET_DATA_SOURCE] 39 | 40 | onNewData: (sourceName, data) => { 41 | // run just once 42 | connectedSources.length = 0 43 | 44 | if (data['exit code'] > 0) { 45 | print(data.stderr) 46 | } else { 47 | const transferData = Utils.parseTransferData(data.stdout) 48 | 49 | interfacesWhitelist.model.clear() 50 | 51 | for (const name of plasmoid.configuration.interfacesWhitelist) { 52 | interfacesWhitelist.model.append({ name, shown: true }) 53 | } 54 | 55 | for (var name in transferData) { 56 | if (plasmoid.configuration.interfacesWhitelist.indexOf(name) !== -1) { 57 | continue 58 | } 59 | 60 | interfacesWhitelist.model.append({ name, shown: false }) 61 | } 62 | } 63 | } 64 | } 65 | 66 | ListModel { 67 | id: interfacesModel 68 | } 69 | 70 | GridLayout { 71 | columns: 2 72 | 73 | CheckBox { 74 | id: launchApplicationEnabled 75 | text: i18n('Launch application when clicked:') 76 | enabled: launcher.item != null 77 | } 78 | 79 | AppPicker { 80 | id: launchApplication 81 | enabled: launcher.item != null && launchApplicationEnabled.checked 82 | } 83 | 84 | Text { 85 | text: i18n('If you want to lauch an application,\nyou need to install the package plasma-addons first.') 86 | visible: launcher.item == null 87 | Layout.columnSpan: 2 88 | } 89 | 90 | CheckBox { 91 | id: interfacesWhitelistEnabled 92 | text: i18n('Show only the following network interfaces:') 93 | Layout.columnSpan: 2 94 | } 95 | 96 | Rectangle { 97 | height: 200 98 | border { 99 | width: 1 100 | color: Kirigami.Theme.alternateBackgroundColor 101 | } 102 | radius: 2 103 | color: Kirigami.Theme.backgroundColor 104 | Layout.columnSpan: 2 105 | Layout.fillWidth: true 106 | 107 | ScrollView { 108 | anchors.fill: parent 109 | 110 | ListView { 111 | id: interfacesWhitelist 112 | anchors.fill: parent 113 | clip: true 114 | Layout.columnSpan: 2 115 | 116 | model: interfacesModel 117 | 118 | delegate: Item { 119 | id: interfaceItem 120 | height: Kirigami.Units.iconSizes.smallMedium + 2*Kirigami.Units.smallSpacing 121 | 122 | property bool isHovered: false 123 | 124 | CheckBox { 125 | x: Kirigami.Units.smallSpacing 126 | y: Kirigami.Units.smallSpacing 127 | 128 | text: name 129 | checked: shown 130 | enabled: interfacesWhitelistEnabled.checked 131 | 132 | onCheckedChanged: { 133 | var index = cfg_interfacesWhitelist.indexOf(name) 134 | if (checked && index === -1) { 135 | cfg_interfacesWhitelist.push(name) 136 | } else if (!checked && index !== -1) { 137 | cfg_interfacesWhitelist.splice(index, 1) 138 | } 139 | } 140 | } 141 | } 142 | } 143 | } 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /package/contents/ui/config/ConfigGeneral.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Daniel Faust 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | import QtQuick 18 | import QtQuick.Controls 19 | import QtQuick.Layouts 20 | import org.kde.kirigami as Kirigami 21 | 22 | Kirigami.FormLayout { 23 | property alias cfg_showSeparately: showSeparately.checked 24 | property alias cfg_showLowSpeeds: showLowSpeeds.checked 25 | property string cfg_speedLayout: 'auto' 26 | property bool cfg_swapDownUp: false 27 | property alias cfg_showIcons: showIcons.checked 28 | property alias cfg_showUnits: showUnits.checked 29 | property string cfg_speedUnits: 'bytes' 30 | property alias cfg_shortUnits: shortUnits.checked 31 | property alias cfg_fontSize: fontSize.value 32 | property alias cfg_updateInterval: updateInterval.value 33 | property alias cfg_customColors: customColors.checked 34 | property alias cfg_byteColor: byteColorPicker.chosenColor 35 | property alias cfg_kilobyteColor: kilobyteColorPicker.chosenColor 36 | property alias cfg_megabyteColor: megabyteColorPicker.chosenColor 37 | property alias cfg_gigabyteColor: gigabyteColorPicker.chosenColor 38 | 39 | GridLayout { 40 | columns: 2 41 | 42 | Label { 43 | text: i18n('Layout:') 44 | } 45 | 46 | ComboBox { 47 | id: speedLayout 48 | textRole: 'label' 49 | model: [ 50 | { 51 | 'label': i18n('Automatic'), 52 | 'value': 'auto' 53 | }, 54 | { 55 | 'label': i18n('Above each other'), 56 | 'value': 'rows' 57 | }, 58 | { 59 | 'label': i18n('Side by side'), 60 | 'value': 'columns' 61 | } 62 | ] 63 | onCurrentIndexChanged: cfg_speedLayout = model[currentIndex]['value'] 64 | 65 | Component.onCompleted: { 66 | for (var i = 0; i < model.length; i++) { 67 | if (model[i]['value'] == plasmoid.configuration.speedLayout) { 68 | speedLayout.currentIndex = i 69 | } 70 | } 71 | } 72 | } 73 | 74 | Label { 75 | text: i18n('Display order:') 76 | } 77 | 78 | ComboBox { 79 | id: displayOrder 80 | textRole: 'label' 81 | model: [ 82 | { 83 | 'label': i18n('Show upload speed first'), 84 | 'value': 'up' 85 | }, 86 | { 87 | 'label': i18n('Show download speed first'), 88 | 'value': 'down' 89 | } 90 | ] 91 | onCurrentIndexChanged: cfg_swapDownUp = model[currentIndex]['value'] == 'up' 92 | 93 | Component.onCompleted: { 94 | if (plasmoid.configuration.swapDownUp) { 95 | displayOrder.currentIndex = 0 96 | } else { 97 | displayOrder.currentIndex = 1 98 | } 99 | } 100 | } 101 | 102 | Label { 103 | text: i18n('Speed units:') 104 | } 105 | 106 | ComboBox { 107 | id: speedUnits 108 | textRole: 'label' 109 | model: [ 110 | { 111 | 'label': i18n('Bits'), 112 | 'value': 'bits' 113 | }, 114 | { 115 | 'label': i18n('Bytes'), 116 | 'value': 'bytes' 117 | } 118 | ] 119 | onCurrentIndexChanged: cfg_speedUnits = model[currentIndex]['value'] 120 | 121 | Component.onCompleted: { 122 | for (var i = 0; i < model.length; i++) { 123 | if (model[i]['value'] == plasmoid.configuration.speedUnits) { 124 | speedUnits.currentIndex = i 125 | } 126 | } 127 | } 128 | 129 | property string currentVal: model[currentIndex]['value'] 130 | } 131 | 132 | CheckBox { 133 | id: showUnits 134 | text: i18n('Show speed units') 135 | Layout.columnSpan: 2 136 | } 137 | 138 | CheckBox { 139 | id: shortUnits 140 | text: i18n('Use shortened speed units') 141 | Layout.columnSpan: 2 142 | enabled: showUnits.checked 143 | } 144 | 145 | CheckBox { 146 | id: showIcons 147 | text: i18n('Show upload and download icons') 148 | Layout.columnSpan: 2 149 | } 150 | 151 | CheckBox { 152 | id: showSeparately 153 | text: i18n('Show download and upload speed separately') 154 | Layout.columnSpan: 2 155 | } 156 | 157 | CheckBox { 158 | id: showLowSpeeds 159 | text: i18n('Show speeds below 1 kb/s') 160 | Layout.columnSpan: 2 161 | } 162 | 163 | Label { 164 | text: i18n('Font size:') 165 | } 166 | 167 | SpinBox { 168 | id: fontSize 169 | from: 10 170 | to: 200 171 | stepSize: 5 172 | textFromValue: function(value) { return value + ' %'; } 173 | valueFromText: function(text) { return Number(text.remove(RegExp(' %$'))); } 174 | } 175 | 176 | Label { 177 | text: i18n('Update interval:') 178 | } 179 | 180 | SpinBox { 181 | id: updateInterval 182 | from: 1 183 | to: 10 184 | stepSize: 1 185 | textFromValue: function(value) { return value + ' s'; } 186 | valueFromText: function(text) { return Number(text.remove(RegExp(' s$'))); } 187 | } 188 | 189 | GroupBox { 190 | label: CheckBox { 191 | id: customColors 192 | text: 'Use custom colors' 193 | } 194 | Layout.columnSpan: 2 195 | 196 | GridLayout { 197 | anchors.fill: parent 198 | anchors.margins: Kirigami.Units.smallSpacing 199 | columns: 2 200 | 201 | Label { 202 | text: { 203 | if (speedUnits.currentVal === 'bits') { 204 | return shortUnits.checked ? 'b' : 'b/s:' 205 | } else { 206 | return shortUnits.checked ? 'B' : 'B/s:' 207 | } 208 | } 209 | Layout.alignment: Qt.AlignRight 210 | } 211 | 212 | ColorPicker { 213 | id: byteColorPicker 214 | } 215 | 216 | Label { 217 | text: { 218 | if (speedUnits.currentVal === 'bits') { 219 | return shortUnits.checked ? 'k:' : 'kb/s:' 220 | } else { 221 | return shortUnits.checked ? 'K:' : 'KiB/s:' 222 | } 223 | } 224 | Layout.alignment: Qt.AlignRight 225 | } 226 | 227 | ColorPicker { 228 | id: kilobyteColorPicker 229 | } 230 | 231 | Label { 232 | text: { 233 | if (speedUnits.currentVal === 'bits') { 234 | return shortUnits.checked ? 'm:' : 'Mb/s:' 235 | } else { 236 | return shortUnits.checked ? 'M:' : 'MiB/s:' 237 | } 238 | } 239 | Layout.alignment: Qt.AlignRight 240 | } 241 | 242 | ColorPicker { 243 | id: megabyteColorPicker 244 | } 245 | 246 | Label { 247 | text: { 248 | if (speedUnits.currentVal === 'bits') { 249 | return shortUnits.checked ? 'g:' : 'Gb/s:' 250 | } else { 251 | return shortUnits.checked ? 'G:' : 'GiB/s:' 252 | } 253 | } 254 | Layout.alignment: Qt.AlignRight 255 | } 256 | 257 | ColorPicker { 258 | id: gigabyteColorPicker 259 | } 260 | } 261 | } 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /package/contents/ui/main.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 Daniel Faust 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License as 6 | * published by the Free Software Foundation; either version 2 of 7 | * the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | import QtQuick 18 | import org.kde.plasma.plasmoid 19 | import org.kde.plasma.plasma5support as Plasma5Support 20 | import "../code/utils.js" as Utils 21 | 22 | PlasmoidItem { 23 | property bool showSeparately: plasmoid.configuration.showSeparately 24 | property bool showLowSpeeds: plasmoid.configuration.showLowSpeeds 25 | property string speedLayout: plasmoid.configuration.speedLayout 26 | property bool swapDownUp: plasmoid.configuration.swapDownUp 27 | property bool showIcons: plasmoid.configuration.showIcons 28 | property bool showUnits: plasmoid.configuration.showUnits 29 | property string speedUnits: plasmoid.configuration.speedUnits 30 | property bool shortUnits: plasmoid.configuration.shortUnits 31 | property double fontSizeScale: plasmoid.configuration.fontSize / 100 32 | property double updateInterval: plasmoid.configuration.updateInterval 33 | property bool customColors: plasmoid.configuration.customColors 34 | property color byteColor: plasmoid.configuration.byteColor 35 | property color kilobyteColor: plasmoid.configuration.kilobyteColor 36 | property color megabyteColor: plasmoid.configuration.megabyteColor 37 | property color gigabyteColor: plasmoid.configuration.gigabyteColor 38 | 39 | property bool launchApplicationEnabled: plasmoid.configuration.launchApplicationEnabled 40 | property string launchApplication: plasmoid.configuration.launchApplication 41 | property bool interfacesWhitelistEnabled: plasmoid.configuration.interfacesWhitelistEnabled 42 | property var interfacesWhitelist: plasmoid.configuration.interfacesWhitelist 43 | 44 | property var transferDataTs: 0 45 | property var transferData: {} 46 | property var speedData: {} 47 | 48 | // For some reason, ToolTipAreas only work with fullRepresentation now 49 | fullRepresentation: CompactRepresentation {} 50 | preferredRepresentation: fullRepresentation 51 | 52 | Plasma5Support.DataSource { 53 | id: dataSource 54 | engine: 'executable' 55 | connectedSources: [Utils.NET_DATA_SOURCE] 56 | interval: updateInterval * 1000 57 | 58 | onNewData: (sourceName, data) => { 59 | if (data['exit code'] > 0) { 60 | print(data.stderr) 61 | } else { 62 | const now = Date.now() 63 | const duration = now - transferDataTs 64 | const nextTransferData = Utils.parseTransferData(data.stdout) 65 | 66 | speedData = Utils.calcSpeedData(transferData, nextTransferData, duration) 67 | 68 | transferDataTs = now 69 | transferData = nextTransferData 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /package/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "KPlugin": { 3 | "Authors": [ 4 | { 5 | "Email": "hessijames@gmail.com", 6 | "Name": "Daniel Faust" 7 | } 8 | ], 9 | "Category": "System Information", 10 | "Description": "Displays the currently used network bandwidth", 11 | "Icon": "network-connect", 12 | "Id": "org.kde.netspeedWidget", 13 | "License": "GPL2", 14 | "Name": "Netspeed Widget", 15 | "KPackageStructure": [ 16 | "Plasma/Applet" 17 | ], 18 | "Version": "3.1", 19 | "Website": "https://github.com/dfaust/plasma-applet-netspeed-widget" 20 | }, 21 | "X-KDE-ParentApp": "", 22 | "X-Plasma-API-Minimum-Version": "6.0", 23 | "X-Plasma-MainScript": "ui/main.qml", 24 | "X-Plasma-RemoteLocation": "" 25 | } 26 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/env bash 2 | 3 | if [ -e "netspeed-widget-$1.plasmoid" ]; then 4 | echo "File \`netspeed-widget-$1.plasmoid\` alread exists" 5 | exit 6 | fi 7 | 8 | pushd package 9 | 10 | zip -r ../netspeed-widget-$1.plasmoid * 11 | 12 | popd 13 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/env bash 2 | 3 | plasmawindowed org.kde.netspeedWidget 4 | --------------------------------------------------------------------------------