diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/LICENSE b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/LICENSE deleted file mode 100644 index f288702..0000000 --- a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/README.md b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/README.md deleted file mode 100644 index a815963..0000000 --- a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/README.md +++ /dev/null @@ -1,212 +0,0 @@ -# Claude Usage Widget - -A KDE Plasma 6 widget that displays your Claude Code usage statistics in the taskbar. - -![Popup](screenshots/popup.png) - -## Features - -- **Compact Panel Display**: Shows session and weekly usage percentages right in your taskbar - ![Panel](screenshots/panel.png) -- **Color-coded Indicators**: Green (<50%), Yellow (<80%), Red (≥80%) -- **Detailed Popup**: Click to see full statistics - - Session and weekly usage with progress bars - - Reset times for both limits - - Per-model breakdown (Sonnet/Opus) - - Your subscription plan badge -- **Configurable Refresh**: Default 5 min polling (adjustable in settings) -- **Smart Rate Limit Handling**: Uses `retry-after` header, exponential backoff, and token watcher for automatic recovery -- **Local Cache**: Remembers last data on restart (up to 24h) -- **Stale Detection**: Widget dims when data is outdated -- **Error Handling**: Clear messages when not logged in, token expired, or rate limited -- **Custom API Support**: Optional proxy/gateway with custom base URL and API key -- **15 Languages**: EN, HU, DE, FR, ES, IT, PT, RU, PL, NL, TR, JA, KO, ZH-CN, ZH-TW -- **No Dependencies**: Pure QML, no Python or external tools required - -## Requirements - -- KDE Plasma 6.0 or later -- Claude Code CLI installed and logged in - -## Installation - -### From KDE Store - -1. Right-click on your panel -2. Select "Add Widgets..." -3. Click "Get New Widgets..." > "Download New Plasma Widgets..." -4. Search for "Claude Usage" -5. Click Install - -### Manual Installation - -```bash -kpackagetool6 -t Plasma/Applet -i claude-usage-widget.plasmoid -``` - -### From Source - -```bash -git clone https://github.com/izll/plasma-claude-usage.git -cd claude-usage-widget -kpackagetool6 -t Plasma/Applet -i . -``` - -## Usage - -1. Make sure you're logged in to Claude Code (run `claude` in terminal) -2. Add the widget to your panel -3. Click the widget to see detailed usage statistics - -## Configuration - -Right-click the widget and select **Configure...** to open the settings. - -### Custom API Base URL (optional) - -By default the widget reads your OAuth credentials from `~/.claude/.credentials.json` and calls `https://api.anthropic.com` directly — no configuration needed. - -If you use a custom API proxy or gateway, you can override this: - -| Setting | Description | -|---|---| -| **Base URL** | Your proxy URL, e.g. `https://your-proxy.example.com` | -| **API key** | Your `ANTHROPIC_API_KEY` | - -> **Note:** The widget calls `/api/oauth/usage`, not the standard `/v1/messages` endpoint. Use the root URL without any path suffix — e.g. `https://api.anthropic.com`, not `https://api.anthropic.com/v1`. - -When a base URL is configured, the widget authenticates with `x-api-key` instead of the OAuth token. Leave the Base URL field empty to go back to the default credentials file method. - -## How It Works - -The widget calls the Anthropic usage API directly from QML. No data is stored or sent anywhere else. - -### API Endpoint - -``` -GET https://api.anthropic.com/api/oauth/usage -Headers: - Authorization: Bearer (default mode) - x-api-key: (custom base URL mode) - anthropic-beta: oauth-2025-04-20 -``` - -## Troubleshooting - -### "Not logged in" error - -Make sure you're logged in to Claude Code: -```bash -claude -``` - -### "Token expired" error - -Your OAuth token has expired. Run Claude Code again to refresh it: -```bash -claude -``` -The widget also has an "Open Claude" button for this. - -### "Rate limited" error - -The API allows ~4 requests per 5-minute window. The widget handles this automatically: -- Reads the `retry-after` header and waits the specified time -- Falls back to exponential backoff (5/10/15 min) -- Monitors for token refresh and recovers instantly - -To avoid rate limiting, keep the refresh interval at 5 minutes or higher. - -### "Invalid API key" error - -The API key in the widget settings is wrong or revoked. Open **Configure...** and update it. - -### "Endpoint not found — check base URL" error - -The base URL in the widget settings doesn't point to a valid API. Make sure you're using the root URL without `/v1`, e.g. `https://api.anthropic.com`. - -### Widget shows 0% - -- Click the refresh button in the popup -- Check logs: `journalctl --user -f | grep -i claude` - -## File Structure - -``` -claude-usage-widget/ -├── metadata.json # Widget metadata -├── install.sh # Installation script -├── contents/ -│ ├── config/ -│ │ └── main.xml # Configuration schema -│ ├── ui/ -│ │ ├── main.qml # Widget implementation -│ │ ├── configGeneral.qml # Settings UI -│ │ └── Translations.qml # i18n (15 languages) -│ └── icons/ -│ └── claude.svg # Claude logo (orange) -└── screenshots/ # Preview images -``` - -## License - -GPL-3.0-or-later - -## Author - -izll - -## Version History - -### 1.3.6 (2026) -- Vertical layout option for taller panels (thanks @nahall, issue #5) -- Panel metrics can now be stacked vertically to save horizontal space - -### 1.3.5 (2026) -- Widget picker now shows proper preview image (progress ring + Claude logo + USAGE) -- About page shows correct icon via auto-install to system icon theme -- New `contents/screenshot.png` for KPackage widget picker preview - -### 1.3.2 (2026) -- Fix widget icon not showing in panel widget picker dialog - -### 1.3.1 (2026) -- Configurable background opacity for desktop mode (thanks @Endle) -- Background opacity only applies on desktop, panel keeps default Plasma theme -- Default opacity set to 100% for consistent upgrade experience - -### 1.3.0 (2026) -- Three panel display styles: Text (classic), Circular (ring charts), Bar (vertical bars) -- Claude icon can be hidden in panel -- Tooltip shows all enabled metrics - -### 1.2.5 (2026) -- Configurable panel metrics: choose Session, Weekly, Sonnet independently -- Sonnet weekly usage can now be displayed in the panel (off by default) - -### 1.2.1 (2026) -- Remove false decimal precision from percentage displays (thanks @robinpie) - -### 1.2.0 (2026) -- Smart rate limit handling with `retry-after` header support -- Exponential backoff with automatic recovery -- Token watcher: instantly recovers when Claude Code refreshes the token -- Local data cache: shows last known values on restart (up to 24h) -- Stale detection: widget dims when data is outdated -- Default refresh interval changed to 5 min to prevent rate limiting -- Rate limit warning in popup and settings for intervals under 5 min - -### 1.1.0 (2026) -- Custom API base URL and API key support for proxy/gateway users -- 429 rate limit handling with auto-retry -- Token expired state with "Open Claude" button -- Dynamic Claude Code version detection for User-Agent -- All strings translated across 15 languages -- Install script added - -### 1.0.0 (2025) -- Initial release -- Session and weekly usage display -- Per-model breakdown (Sonnet/Opus) -- Configurable refresh interval -- Error handling for login issues diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/claude-usage-widget.plasmoid b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/claude-usage-widget.plasmoid deleted file mode 100644 index fa1490e..0000000 Binary files a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/claude-usage-widget.plasmoid and /dev/null differ diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/config/config.qml b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/config/config.qml deleted file mode 100644 index 0c93c6b..0000000 --- a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/config/config.qml +++ /dev/null @@ -1,15 +0,0 @@ -/* - SPDX-FileCopyrightText: 2025 izll - SPDX-License-Identifier: GPL-3.0-or-later -*/ - -import QtQuick -import org.kde.plasma.configuration - -ConfigModel { - ConfigCategory { - name: i18n("General") - icon: "configure" - source: "configGeneral.qml" - } -} diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/config/main.xml b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/config/main.xml deleted file mode 100644 index ce35a43..0000000 --- a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/config/main.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - system - - - - 5 - - - - horizontal - - - - true - - - - text - - - - true - - - - true - - - - false - - - - - - - - - - - - 1.0 - - - diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/icons/claude-usage-widget.svg b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/icons/claude-usage-widget.svg deleted file mode 100644 index a75ed63..0000000 --- a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/icons/claude-usage-widget.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - USAGE - diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/icons/claude.svg b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/icons/claude.svg deleted file mode 100644 index cb5dce1..0000000 --- a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/icons/claude.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/icons/widget.svg b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/icons/widget.svg deleted file mode 100644 index 4afe9b6..0000000 --- a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/icons/widget.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/screenshot.png b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/screenshot.png deleted file mode 100644 index bb1c948..0000000 Binary files a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/screenshot.png and /dev/null differ diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/ui/Translations.qml b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/ui/Translations.qml deleted file mode 100644 index 88858b7..0000000 --- a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/ui/Translations.qml +++ /dev/null @@ -1,790 +0,0 @@ -/* - SPDX-FileCopyrightText: 2025 izll - SPDX-License-Identifier: GPL-3.0-or-later -*/ - -import QtQuick - -QtObject { - id: translations - - property string currentLanguage: "system" - property int version: 0 - - onCurrentLanguageChanged: { - version++; - } - - readonly property var strings: ({ - "en_US": { - "Claude Usage": "Claude Usage", - "Session (5hr)": "Session (5hr)", - "Weekly (7day)": "Weekly (7day)", - "By Model (Weekly)": "By Model (Weekly)", - "Sonnet": "Sonnet", - "Opus": "Opus", - "Resets at:": "Resets at:", - "Resets:": "Resets:", - "Updated:": "Updated:", - "Loading...": "Loading...", - "Refresh": "Refresh", - "Not logged in": "Not logged in", - "Token expired": "Token expired", - "API error": "API error", - "Run 'claude' to log in": "Run 'claude' to log in", - "No model breakdown available": "No model breakdown available", - "Language:": "Language:", - "System default": "System default", - "d": "d", - "h": "h", - "m": "m", - "Refresh interval:": "Refresh interval:", - "minutes": "minutes", - "Open Claude": "Open Claude", - "Rate limited": "Rate limited", - "Auto-retry in 1 min": "Auto-retry in 1 min", - "Custom API (optional)": "Custom API (optional)", - "Base URL:": "Base URL:", - "API key:": "API key:", - "Leave empty to use ~/.claude/.credentials.json (default)": "Leave empty to use ~/.claude/.credentials.json (default)", - "Check base URL and API key in widget settings": "Check base URL and API key in widget settings", - "API key not configured": "API key not configured", - "Invalid API key": "Invalid API key", - "Endpoint not found": "Endpoint not found", - "Values under 5 min may cause rate limiting": "Values under 5 min may cause rate limiting", - "Panel display": "Panel display", - "Show in panel:": "Show in panel:", - "Icon:": "Icon:", - "Show Claude icon": "Show Claude icon", - "Style:": "Style:", - "Text": "Text", - "Circular": "Circular", - "Bar": "Bar", - "Layout:": "Layout:", - "Horizontal": "Horizontal", - "Vertical": "Vertical", - "Background opacity (desktop):": "Background opacity (desktop):" - }, - "hu_HU": { - "Claude Usage": "Claude használat", - "Session (5hr)": "Munkamenet (5 óra)", - "Weekly (7day)": "Heti (7 nap)", - "By Model (Weekly)": "Modell szerint (Heti)", - "Sonnet": "Sonnet", - "Opus": "Opus", - "Resets at:": "Visszaáll:", - "Resets:": "Visszaáll:", - "Updated:": "Frissítve:", - "Loading...": "Betöltés...", - "Refresh": "Frissítés", - "Not logged in": "Nincs bejelentkezve", - "Token expired": "Lejárt token", - "API error": "API hiba", - "Run 'claude' to log in": "Futtasd a 'claude' parancsot", - "No model breakdown available": "Nincs modell bontás", - "Language:": "Nyelv:", - "System default": "Rendszer alapértelmezett", - "d": "n", - "h": "ó", - "m": "p", - "Refresh interval:": "Frissítési gyakoriság:", - "minutes": "perc", - "Open Claude": "Claude megnyitása", - "Rate limited": "Korlát elérve", - "Auto-retry in 1 min": "Automatikus újrapróbálás 1 perc múlva", - "Custom API (optional)": "Egyéni API (opcionális)", - "Base URL:": "Alap URL:", - "API key:": "API kulcs:", - "Leave empty to use ~/.claude/.credentials.json (default)": "Hagyd üresen a ~/.claude/.credentials.json használatához (alapértelmezett)", - "Check base URL and API key in widget settings": "Ellenőrizd az alap URL-t és API kulcsot a widget beállításokban", - "API key not configured": "API kulcs nincs beállítva", - "Invalid API key": "Érvénytelen API kulcs", - "Endpoint not found": "Végpont nem található", - "Values under 5 min may cause rate limiting": "5 perc alatti értékek rate limitet okozhatnak", - "Panel display": "Panel megjelenítés", - "Show in panel:": "Megjelenítés a panelen:", - "Icon:": "Ikon:", - "Show Claude icon": "Claude ikon megjelenítése", - "Style:": "Stílus:", - "Text": "Szöveges", - "Circular": "Kördiagram", - "Bar": "Sávdiagram", - "Layout:": "Elrendezés:", - "Horizontal": "Vízszintes", - "Vertical": "Függőleges", - "Background opacity (desktop):": "Háttér átlátszóság (asztal):" - }, - "de_DE": { - "Claude Usage": "Claude Nutzung", - "Session (5hr)": "Sitzung (5 Std)", - "Weekly (7day)": "Wöchentlich (7 Tage)", - "By Model (Weekly)": "Nach Modell (Wöchentlich)", - "Sonnet": "Sonnet", - "Opus": "Opus", - "Resets at:": "Setzt zurück um:", - "Resets:": "Setzt zurück:", - "Updated:": "Aktualisiert:", - "Loading...": "Laden...", - "Refresh": "Aktualisieren", - "Not logged in": "Nicht angemeldet", - "Token expired": "Token abgelaufen", - "API error": "API-Fehler", - "Run 'claude' to log in": "Führen Sie 'claude' aus", - "No model breakdown available": "Keine Modellaufschlüsselung verfügbar", - "Language:": "Sprache:", - "System default": "Systemstandard", - "d": "T", - "h": "Std", - "m": "Min", - "Refresh interval:": "Aktualisierungsintervall:", - "minutes": "Minuten", - "Open Claude": "Claude öffnen", - "Rate limited": "Rate-Limit erreicht", - "Auto-retry in 1 min": "Automatische Wiederholung in 1 Min", - "Custom API (optional)": "Benutzerdefinierte API (optional)", - "Base URL:": "Basis-URL:", - "API key:": "API-Schlüssel:", - "Leave empty to use ~/.claude/.credentials.json (default)": "Leer lassen für ~/.claude/.credentials.json (Standard)", - "Check base URL and API key in widget settings": "Überprüfen Sie Basis-URL und API-Schlüssel in den Widget-Einstellungen", - "API key not configured": "API-Schlüssel nicht konfiguriert", - "Invalid API key": "Ungültiger API-Schlüssel", - "Endpoint not found": "Endpunkt nicht gefunden", - "Values under 5 min may cause rate limiting": "Werte unter 5 Min können Rate-Limiting verursachen", - "Panel display": "Panel-Anzeige", - "Show in panel:": "Im Panel anzeigen:", - "Icon:": "Symbol:", - "Show Claude icon": "Claude-Symbol anzeigen", - "Style:": "Stil:", - "Text": "Text", - "Circular": "Kreisförmig", - "Bar": "Balken", - "Layout:": "Layout:", - "Horizontal": "Horizontal", - "Vertical": "Vertikal", - "Background opacity (desktop):": "Hintergrund-Deckkraft (Desktop):" - }, - "fr_FR": { - "Claude Usage": "Utilisation Claude", - "Session (5hr)": "Session (5h)", - "Weekly (7day)": "Hebdomadaire (7j)", - "By Model (Weekly)": "Par modèle (Hebdo)", - "Sonnet": "Sonnet", - "Opus": "Opus", - "Resets at:": "Réinitialisation à:", - "Resets:": "Réinitialisation:", - "Updated:": "Mis à jour:", - "Loading...": "Chargement...", - "Refresh": "Actualiser", - "Not logged in": "Non connecté", - "Token expired": "Token expiré", - "API error": "Erreur API", - "Run 'claude' to log in": "Exécutez 'claude' pour vous connecter", - "No model breakdown available": "Pas de détail par modèle", - "Language:": "Langue:", - "System default": "Système par défaut", - "d": "j", - "h": "h", - "m": "min", - "Refresh interval:": "Intervalle de rafraîchissement:", - "minutes": "minutes", - "Open Claude": "Ouvrir Claude", - "Rate limited": "Limite atteinte", - "Auto-retry in 1 min": "Nouvel essai auto dans 1 min", - "Custom API (optional)": "API personnalisée (optionnel)", - "Base URL:": "URL de base:", - "API key:": "Clé API:", - "Leave empty to use ~/.claude/.credentials.json (default)": "Laisser vide pour utiliser ~/.claude/.credentials.json (par défaut)", - "Check base URL and API key in widget settings": "Vérifiez l'URL de base et la clé API dans les paramètres", - "API key not configured": "Clé API non configurée", - "Invalid API key": "Clé API invalide", - "Endpoint not found": "Point d'accès introuvable", - "Values under 5 min may cause rate limiting": "Les valeurs inférieures à 5 min peuvent causer un rate limiting", - "Panel display": "Affichage du panneau", - "Show in panel:": "Afficher dans le panneau:", - "Icon:": "Icône:", - "Show Claude icon": "Afficher l'icône Claude", - "Style:": "Style:", - "Text": "Texte", - "Circular": "Circulaire", - "Bar": "Barre", - "Layout:": "Disposition:", - "Horizontal": "Horizontal", - "Vertical": "Vertical", - "Background opacity (desktop):": "Opacité du fond (bureau):" - }, - "es_ES": { - "Claude Usage": "Uso de Claude", - "Session (5hr)": "Sesión (5h)", - "Weekly (7day)": "Semanal (7 días)", - "By Model (Weekly)": "Por modelo (Semanal)", - "Sonnet": "Sonnet", - "Opus": "Opus", - "Resets at:": "Se reinicia a las:", - "Resets:": "Se reinicia:", - "Updated:": "Actualizado:", - "Loading...": "Cargando...", - "Refresh": "Actualizar", - "Not logged in": "No conectado", - "Token expired": "Token expirado", - "API error": "Error de API", - "Run 'claude' to log in": "Ejecuta 'claude' para iniciar sesión", - "No model breakdown available": "Sin desglose por modelo", - "Language:": "Idioma:", - "System default": "Predeterminado del sistema", - "d": "d", - "h": "h", - "m": "min", - "Refresh interval:": "Intervalo de actualización:", - "minutes": "minutos", - "Open Claude": "Abrir Claude", - "Rate limited": "Límite alcanzado", - "Auto-retry in 1 min": "Reintento automático en 1 min", - "Custom API (optional)": "API personalizada (opcional)", - "Base URL:": "URL base:", - "API key:": "Clave API:", - "Leave empty to use ~/.claude/.credentials.json (default)": "Dejar vacío para usar ~/.claude/.credentials.json (predeterminado)", - "Check base URL and API key in widget settings": "Verifica la URL base y la clave API en la configuración del widget", - "API key not configured": "Clave API no configurada", - "Invalid API key": "Clave API inválida", - "Endpoint not found": "Punto de acceso no encontrado", - "Values under 5 min may cause rate limiting": "Valores menores a 5 min pueden causar rate limiting", - "Panel display": "Visualización del panel", - "Show in panel:": "Mostrar en el panel:", - "Icon:": "Icono:", - "Show Claude icon": "Mostrar icono de Claude", - "Style:": "Estilo:", - "Text": "Texto", - "Circular": "Circular", - "Bar": "Barra", - "Layout:": "Disposición:", - "Horizontal": "Horizontal", - "Vertical": "Vertical", - "Background opacity (desktop):": "Opacidad del fondo (escritorio):" - }, - "it_IT": { - "Claude Usage": "Utilizzo Claude", - "Session (5hr)": "Sessione (5h)", - "Weekly (7day)": "Settimanale (7gg)", - "By Model (Weekly)": "Per modello (Settimanale)", - "Sonnet": "Sonnet", - "Opus": "Opus", - "Resets at:": "Si azzera alle:", - "Resets:": "Si azzera:", - "Updated:": "Aggiornato:", - "Loading...": "Caricamento...", - "Refresh": "Aggiorna", - "Not logged in": "Non connesso", - "Token expired": "Token scaduto", - "API error": "Errore API", - "Run 'claude' to log in": "Esegui 'claude' per accedere", - "No model breakdown available": "Nessun dettaglio per modello", - "Language:": "Lingua:", - "System default": "Predefinito di sistema", - "d": "g", - "h": "h", - "m": "min", - "Refresh interval:": "Intervallo di aggiornamento:", - "minutes": "minuti", - "Open Claude": "Apri Claude", - "Rate limited": "Limite raggiunto", - "Auto-retry in 1 min": "Riprova automatica tra 1 min", - "Custom API (optional)": "API personalizzata (opzionale)", - "Base URL:": "URL base:", - "API key:": "Chiave API:", - "Leave empty to use ~/.claude/.credentials.json (default)": "Lasciare vuoto per usare ~/.claude/.credentials.json (predefinito)", - "Check base URL and API key in widget settings": "Controlla URL base e chiave API nelle impostazioni del widget", - "API key not configured": "Chiave API non configurata", - "Invalid API key": "Chiave API non valida", - "Endpoint not found": "Endpoint non trovato", - "Values under 5 min may cause rate limiting": "Valori sotto 5 min possono causare rate limiting", - "Panel display": "Visualizzazione pannello", - "Show in panel:": "Mostra nel pannello:", - "Icon:": "Icona:", - "Show Claude icon": "Mostra icona Claude", - "Style:": "Stile:", - "Text": "Testo", - "Circular": "Circolare", - "Bar": "Barra", - "Layout:": "Disposizione:", - "Horizontal": "Orizzontale", - "Vertical": "Verticale", - "Background opacity (desktop):": "Opacità sfondo (desktop):" - }, - "pt_BR": { - "Claude Usage": "Uso do Claude", - "Session (5hr)": "Sessão (5h)", - "Weekly (7day)": "Semanal (7 dias)", - "By Model (Weekly)": "Por modelo (Semanal)", - "Sonnet": "Sonnet", - "Opus": "Opus", - "Resets at:": "Reinicia às:", - "Resets:": "Reinicia:", - "Updated:": "Atualizado:", - "Loading...": "Carregando...", - "Refresh": "Atualizar", - "Not logged in": "Não conectado", - "Token expired": "Token expirado", - "API error": "Erro de API", - "Run 'claude' to log in": "Execute 'claude' para fazer login", - "No model breakdown available": "Sem detalhamento por modelo", - "Language:": "Idioma:", - "System default": "Padrão do sistema", - "d": "d", - "h": "h", - "m": "min", - "Refresh interval:": "Intervalo de atualização:", - "minutes": "minutos", - "Open Claude": "Abrir Claude", - "Rate limited": "Limite atingido", - "Auto-retry in 1 min": "Tentativa automática em 1 min", - "Custom API (optional)": "API personalizada (opcional)", - "Base URL:": "URL base:", - "API key:": "Chave API:", - "Leave empty to use ~/.claude/.credentials.json (default)": "Deixe vazio para usar ~/.claude/.credentials.json (padrão)", - "Check base URL and API key in widget settings": "Verifique a URL base e a chave API nas configurações do widget", - "API key not configured": "Chave API não configurada", - "Invalid API key": "Chave API inválida", - "Endpoint not found": "Endpoint não encontrado", - "Values under 5 min may cause rate limiting": "Valores abaixo de 5 min podem causar rate limiting", - "Panel display": "Exibição do painel", - "Show in panel:": "Mostrar no painel:", - "Icon:": "Ícone:", - "Show Claude icon": "Mostrar ícone do Claude", - "Style:": "Estilo:", - "Text": "Texto", - "Circular": "Circular", - "Bar": "Barra", - "Layout:": "Layout:", - "Horizontal": "Horizontal", - "Vertical": "Vertical", - "Background opacity (desktop):": "Opacidade do fundo (área de trabalho):" - }, - "ru_RU": { - "Claude Usage": "Использование Claude", - "Session (5hr)": "Сессия (5ч)", - "Weekly (7day)": "Неделя (7 дней)", - "By Model (Weekly)": "По модели (Неделя)", - "Sonnet": "Sonnet", - "Opus": "Opus", - "Resets at:": "Сброс в:", - "Resets:": "Сброс:", - "Updated:": "Обновлено:", - "Loading...": "Загрузка...", - "Refresh": "Обновить", - "Not logged in": "Не авторизован", - "Token expired": "Токен истёк", - "API error": "Ошибка API", - "Run 'claude' to log in": "Запустите 'claude' для входа", - "No model breakdown available": "Нет данных по моделям", - "Language:": "Язык:", - "System default": "По умолчанию системы", - "d": "д", - "h": "ч", - "m": "мин", - "Refresh interval:": "Интервал обновления:", - "minutes": "минут", - "Open Claude": "Открыть Claude", - "Rate limited": "Лимит достигнут", - "Auto-retry in 1 min": "Автоповтор через 1 мин", - "Custom API (optional)": "Пользовательский API (необязательно)", - "Base URL:": "Базовый URL:", - "API key:": "API ключ:", - "Leave empty to use ~/.claude/.credentials.json (default)": "Оставьте пустым для ~/.claude/.credentials.json (по умолчанию)", - "Check base URL and API key in widget settings": "Проверьте базовый URL и API ключ в настройках виджета", - "API key not configured": "API ключ не настроен", - "Invalid API key": "Неверный API ключ", - "Endpoint not found": "Конечная точка не найдена", - "Values under 5 min may cause rate limiting": "Значения менее 5 мин могут вызвать ограничение запросов", - "Panel display": "Отображение панели", - "Show in panel:": "Показывать в панели:", - "Icon:": "Иконка:", - "Show Claude icon": "Показать иконку Claude", - "Style:": "Стиль:", - "Text": "Текст", - "Circular": "Круговой", - "Bar": "Столбик", - "Layout:": "Расположение:", - "Horizontal": "Горизонтально", - "Vertical": "Вертикально", - "Background opacity (desktop):": "Прозрачность фона (рабочий стол):" - }, - "pl_PL": { - "Claude Usage": "Użycie Claude", - "Session (5hr)": "Sesja (5h)", - "Weekly (7day)": "Tygodniowo (7 dni)", - "By Model (Weekly)": "Wg modelu (Tygodniowo)", - "Sonnet": "Sonnet", - "Opus": "Opus", - "Resets at:": "Resetuje o:", - "Resets:": "Resetuje:", - "Updated:": "Zaktualizowano:", - "Loading...": "Ładowanie...", - "Refresh": "Odśwież", - "Not logged in": "Nie zalogowany", - "Token expired": "Token wygasł", - "API error": "Błąd API", - "Run 'claude' to log in": "Uruchom 'claude' aby się zalogować", - "No model breakdown available": "Brak podziału na modele", - "Language:": "Język:", - "System default": "Domyślny systemowy", - "d": "d", - "h": "g", - "m": "min", - "Refresh interval:": "Częstotliwość odświeżania:", - "minutes": "minut", - "Open Claude": "Otwórz Claude", - "Rate limited": "Limit osiągnięty", - "Auto-retry in 1 min": "Automatyczne ponowienie za 1 min", - "Custom API (optional)": "Własne API (opcjonalne)", - "Base URL:": "Bazowy URL:", - "API key:": "Klucz API:", - "Leave empty to use ~/.claude/.credentials.json (default)": "Pozostaw puste aby użyć ~/.claude/.credentials.json (domyślne)", - "Check base URL and API key in widget settings": "Sprawdź bazowy URL i klucz API w ustawieniach widgetu", - "API key not configured": "Klucz API nie skonfigurowany", - "Invalid API key": "Nieprawidłowy klucz API", - "Endpoint not found": "Punkt końcowy nie znaleziony", - "Values under 5 min may cause rate limiting": "Wartości poniżej 5 min mogą powodować rate limiting", - "Panel display": "Wyświetlanie panelu", - "Show in panel:": "Pokaż w panelu:", - "Icon:": "Ikona:", - "Show Claude icon": "Pokaż ikonę Claude", - "Style:": "Styl:", - "Text": "Tekst", - "Circular": "Kołowy", - "Bar": "Pasek", - "Layout:": "Układ:", - "Horizontal": "Poziomy", - "Vertical": "Pionowy", - "Background opacity (desktop):": "Przezroczystość tła (pulpit):" - }, - "nl_NL": { - "Claude Usage": "Claude Gebruik", - "Session (5hr)": "Sessie (5u)", - "Weekly (7day)": "Wekelijks (7 dagen)", - "By Model (Weekly)": "Per model (Wekelijks)", - "Sonnet": "Sonnet", - "Opus": "Opus", - "Resets at:": "Reset om:", - "Resets:": "Reset:", - "Updated:": "Bijgewerkt:", - "Loading...": "Laden...", - "Refresh": "Vernieuwen", - "Not logged in": "Niet ingelogd", - "Token expired": "Token verlopen", - "API error": "API-fout", - "Run 'claude' to log in": "Voer 'claude' uit om in te loggen", - "No model breakdown available": "Geen modeluitsplitsing beschikbaar", - "Language:": "Taal:", - "System default": "Systeemstandaard", - "d": "d", - "h": "u", - "m": "min", - "Refresh interval:": "Vernieuwingsinterval:", - "minutes": "minuten", - "Open Claude": "Claude openen", - "Rate limited": "Limiet bereikt", - "Auto-retry in 1 min": "Automatisch opnieuw over 1 min", - "Custom API (optional)": "Aangepaste API (optioneel)", - "Base URL:": "Basis-URL:", - "API key:": "API-sleutel:", - "Leave empty to use ~/.claude/.credentials.json (default)": "Laat leeg om ~/.claude/.credentials.json te gebruiken (standaard)", - "Check base URL and API key in widget settings": "Controleer basis-URL en API-sleutel in de widgetinstellingen", - "API key not configured": "API-sleutel niet geconfigureerd", - "Invalid API key": "Ongeldige API-sleutel", - "Endpoint not found": "Eindpunt niet gevonden", - "Values under 5 min may cause rate limiting": "Waarden onder 5 min kunnen rate limiting veroorzaken", - "Panel display": "Panelweergave", - "Show in panel:": "Tonen in paneel:", - "Icon:": "Pictogram:", - "Show Claude icon": "Claude-pictogram tonen", - "Style:": "Stijl:", - "Text": "Tekst", - "Circular": "Circulair", - "Bar": "Balk", - "Layout:": "Indeling:", - "Horizontal": "Horizontaal", - "Vertical": "Verticaal", - "Background opacity (desktop):": "Achtergrond dekking (bureaublad):" - }, - "tr_TR": { - "Claude Usage": "Claude Kullanımı", - "Session (5hr)": "Oturum (5sa)", - "Weekly (7day)": "Haftalık (7 gün)", - "By Model (Weekly)": "Modele göre (Haftalık)", - "Sonnet": "Sonnet", - "Opus": "Opus", - "Resets at:": "Sıfırlanma:", - "Resets:": "Sıfırlanma:", - "Updated:": "Güncellendi:", - "Loading...": "Yükleniyor...", - "Refresh": "Yenile", - "Not logged in": "Giriş yapılmadı", - "Token expired": "Token süresi doldu", - "API error": "API hatası", - "Run 'claude' to log in": "Giriş için 'claude' çalıştırın", - "No model breakdown available": "Model dağılımı mevcut değil", - "Language:": "Dil:", - "System default": "Sistem varsayılanı", - "d": "g", - "h": "sa", - "m": "dk", - "Refresh interval:": "Yenileme aralığı:", - "minutes": "dakika", - "Open Claude": "Claude'u Aç", - "Rate limited": "Limit aşıldı", - "Auto-retry in 1 min": "1 dk sonra otomatik yeniden deneme", - "Custom API (optional)": "Özel API (isteğe bağlı)", - "Base URL:": "Temel URL:", - "API key:": "API anahtarı:", - "Leave empty to use ~/.claude/.credentials.json (default)": "Varsayılan ~/.claude/.credentials.json için boş bırakın", - "Check base URL and API key in widget settings": "Widget ayarlarında temel URL ve API anahtarını kontrol edin", - "API key not configured": "API anahtarı yapılandırılmadı", - "Invalid API key": "Geçersiz API anahtarı", - "Endpoint not found": "Uç nokta bulunamadı", - "Values under 5 min may cause rate limiting": "5 dk altındaki değerler rate limiting'e neden olabilir", - "Panel display": "Panel görünümü", - "Show in panel:": "Panelde göster:", - "Icon:": "Simge:", - "Show Claude icon": "Claude simgesini göster", - "Style:": "Stil:", - "Text": "Metin", - "Circular": "Dairesel", - "Bar": "Çubuk", - "Layout:": "Düzen:", - "Horizontal": "Yatay", - "Vertical": "Dikey", - "Background opacity (desktop):": "Arka plan opaklığı (masaüstü):" - }, - "ja_JP": { - "Claude Usage": "Claude 使用状況", - "Session (5hr)": "セッション (5時間)", - "Weekly (7day)": "週間 (7日)", - "By Model (Weekly)": "モデル別 (週間)", - "Sonnet": "Sonnet", - "Opus": "Opus", - "Resets at:": "リセット:", - "Resets:": "リセット:", - "Updated:": "更新:", - "Loading...": "読み込み中...", - "Refresh": "更新", - "Not logged in": "未ログイン", - "Token expired": "トークン期限切れ", - "API error": "APIエラー", - "Run 'claude' to log in": "'claude'を実行してログイン", - "No model breakdown available": "モデル別データなし", - "Language:": "言語:", - "System default": "システムデフォルト", - "d": "日", - "h": "時", - "m": "分", - "Refresh interval:": "更新間隔:", - "minutes": "分", - "Open Claude": "Claudeを開く", - "Rate limited": "レート制限", - "Auto-retry in 1 min": "1分後に自動リトライ", - "Custom API (optional)": "カスタムAPI(オプション)", - "Base URL:": "ベースURL:", - "API key:": "APIキー:", - "Leave empty to use ~/.claude/.credentials.json (default)": "空欄で ~/.claude/.credentials.json を使用(デフォルト)", - "Check base URL and API key in widget settings": "ウィジェット設定でベースURLとAPIキーを確認", - "API key not configured": "APIキー未設定", - "Invalid API key": "無効なAPIキー", - "Endpoint not found": "エンドポイントが見つかりません", - "Values under 5 min may cause rate limiting": "5分未満の値はレート制限を引き起こす可能性があります", - "Panel display": "パネル表示", - "Show in panel:": "パネルに表示:", - "Icon:": "アイコン:", - "Show Claude icon": "Claudeアイコンを表示", - "Style:": "スタイル:", - "Text": "テキスト", - "Circular": "サークル", - "Bar": "バー", - "Layout:": "レイアウト:", - "Horizontal": "横", - "Vertical": "縦", - "Background opacity (desktop):": "背景の不透明度(デスクトップ):" - }, - "ko_KR": { - "Claude Usage": "Claude 사용량", - "Session (5hr)": "세션 (5시간)", - "Weekly (7day)": "주간 (7일)", - "By Model (Weekly)": "모델별 (주간)", - "Sonnet": "Sonnet", - "Opus": "Opus", - "Resets at:": "초기화:", - "Resets:": "초기화:", - "Updated:": "업데이트:", - "Loading...": "로딩 중...", - "Refresh": "새로고침", - "Not logged in": "로그인 안됨", - "Token expired": "토큰 만료", - "API error": "API 오류", - "Run 'claude' to log in": "'claude'를 실행하여 로그인", - "No model breakdown available": "모델별 데이터 없음", - "Language:": "언어:", - "System default": "시스템 기본값", - "d": "일", - "h": "시", - "m": "분", - "Refresh interval:": "새로고침 간격:", - "minutes": "분", - "Open Claude": "Claude 열기", - "Rate limited": "속도 제한", - "Auto-retry in 1 min": "1분 후 자동 재시도", - "Custom API (optional)": "사용자 정의 API (선택사항)", - "Base URL:": "기본 URL:", - "API key:": "API 키:", - "Leave empty to use ~/.claude/.credentials.json (default)": "기본값 ~/.claude/.credentials.json 사용 시 비워두세요", - "Check base URL and API key in widget settings": "위젯 설정에서 기본 URL과 API 키를 확인하세요", - "API key not configured": "API 키 미설정", - "Invalid API key": "잘못된 API 키", - "Endpoint not found": "엔드포인트를 찾을 수 없음", - "Values under 5 min may cause rate limiting": "5분 미만의 값은 속도 제한을 유발할 수 있습니다", - "Panel display": "패널 표시", - "Show in panel:": "패널에 표시:", - "Icon:": "아이콘:", - "Show Claude icon": "Claude 아이콘 표시", - "Style:": "스타일:", - "Text": "텍스트", - "Circular": "원형", - "Bar": "바", - "Layout:": "레이아웃:", - "Horizontal": "가로", - "Vertical": "세로", - "Background opacity (desktop):": "배경 불투명도 (데스크톱):" - }, - "zh_CN": { - "Claude Usage": "Claude 使用情况", - "Session (5hr)": "会话 (5小时)", - "Weekly (7day)": "每周 (7天)", - "By Model (Weekly)": "按模型 (每周)", - "Sonnet": "Sonnet", - "Opus": "Opus", - "Resets at:": "重置时间:", - "Resets:": "重置:", - "Updated:": "更新时间:", - "Loading...": "加载中...", - "Refresh": "刷新", - "Not logged in": "未登录", - "Token expired": "令牌已过期", - "API error": "API 错误", - "Run 'claude' to log in": "运行 'claude' 登录", - "No model breakdown available": "无模型明细", - "Language:": "语言:", - "System default": "系统默认", - "d": "天", - "h": "时", - "m": "分", - "Refresh interval:": "刷新间隔:", - "minutes": "分钟", - "Open Claude": "打开 Claude", - "Rate limited": "速率限制", - "Auto-retry in 1 min": "1分钟后自动重试", - "Custom API (optional)": "自定义API(可选)", - "Base URL:": "基础URL:", - "API key:": "API密钥:", - "Leave empty to use ~/.claude/.credentials.json (default)": "留空以使用 ~/.claude/.credentials.json(默认)", - "Check base URL and API key in widget settings": "请在小部件设置中检查基础URL和API密钥", - "API key not configured": "API密钥未配置", - "Invalid API key": "无效的API密钥", - "Endpoint not found": "端点未找到", - "Values under 5 min may cause rate limiting": "低于5分钟的值可能导致速率限制", - "Panel display": "面板显示", - "Show in panel:": "在面板中显示:", - "Icon:": "图标:", - "Show Claude icon": "显示Claude图标", - "Style:": "样式:", - "Text": "文本", - "Circular": "圆形", - "Bar": "柱状", - "Layout:": "布局:", - "Horizontal": "水平", - "Vertical": "垂直", - "Background opacity (desktop):": "背景不透明度(桌面):" - }, - "zh_TW": { - "Claude Usage": "Claude 使用狀況", - "Session (5hr)": "工作階段 (5小時)", - "Weekly (7day)": "每週 (7天)", - "By Model (Weekly)": "依模型 (每週)", - "Sonnet": "Sonnet", - "Opus": "Opus", - "Resets at:": "重置時間:", - "Resets:": "重置:", - "Updated:": "更新時間:", - "Loading...": "載入中...", - "Refresh": "重新整理", - "Not logged in": "未登入", - "Token expired": "權杖已過期", - "API error": "API 錯誤", - "Run 'claude' to log in": "執行 'claude' 登入", - "No model breakdown available": "無模型明細", - "Language:": "語言:", - "System default": "系統預設", - "d": "天", - "h": "時", - "m": "分", - "Refresh interval:": "重新整理間隔:", - "minutes": "分鐘", - "Open Claude": "開啟 Claude", - "Rate limited": "速率限制", - "Auto-retry in 1 min": "1分鐘後自動重試", - "Custom API (optional)": "自訂API(選填)", - "Base URL:": "基礎URL:", - "API key:": "API金鑰:", - "Leave empty to use ~/.claude/.credentials.json (default)": "留空以使用 ~/.claude/.credentials.json(預設)", - "Check base URL and API key in widget settings": "請在小工具設定中檢查基礎URL和API金鑰", - "API key not configured": "API金鑰未設定", - "Invalid API key": "無效的API金鑰", - "Endpoint not found": "端點未找到", - "Values under 5 min may cause rate limiting": "低於5分鐘的值可能導致速率限制", - "Panel display": "面板顯示", - "Show in panel:": "在面板中顯示:", - "Icon:": "圖標:", - "Show Claude icon": "顯示Claude圖標", - "Style:": "樣式:", - "Text": "文字", - "Circular": "圓形", - "Bar": "柱狀", - "Layout:": "佈局:", - "Horizontal": "水平", - "Vertical": "垂直", - "Background opacity (desktop):": "背景不透明度(桌面):" - } - }) - - readonly property string systemLanguage: { - let locale = Qt.locale().name; - return locale; - } - - function getEffectiveLanguage() { - if (currentLanguage === "system") { - let sysLang = systemLanguage; - if (strings[sysLang]) { - return sysLang; - } - let langCode = sysLang.split("_")[0]; - for (let key in strings) { - if (key.startsWith(langCode + "_")) { - return key; - } - } - return "en_US"; - } - return currentLanguage; - } - - function tr(text) { - let v = version; - let lang = getEffectiveLanguage(); - - if (strings[lang] && strings[lang][text]) { - return strings[lang][text]; - } - if (strings["en_US"] && strings["en_US"][text]) { - return strings["en_US"][text]; - } - return text; - } -} diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/ui/configGeneral.qml b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/ui/configGeneral.qml deleted file mode 100644 index fb0d8cc..0000000 --- a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/ui/configGeneral.qml +++ /dev/null @@ -1,191 +0,0 @@ -/* - SPDX-FileCopyrightText: 2025 izll - SPDX-License-Identifier: GPL-3.0-or-later -*/ - -import QtQuick -import QtQuick.Controls as QQC2 -import QtQuick.Layouts -import org.kde.kirigami as Kirigami -import org.kde.kcmutils as KCM - -KCM.SimpleKCM { - id: configPage - - property string cfg_language - property int cfg_refreshInterval - property string cfg_panelLayout - property bool cfg_showIcon - property string cfg_panelStyle - property bool cfg_showSession - property bool cfg_showWeekly - property bool cfg_showSonnet - property string cfg_baseUrl - property string cfg_apiKey - property double cfg_backgroundOpacity - - // Translation helper - Translations { - id: trans - currentLanguage: cfg_language || "system" - } - - function tr(text) { return trans.tr(text); } - - readonly property var languageValues: [ - "system", "en_US", "hu_HU", "de_DE", "fr_FR", "es_ES", - "it_IT", "pt_BR", "ru_RU", "pl_PL", "nl_NL", "tr_TR", - "ja_JP", "ko_KR", "zh_CN", "zh_TW" - ] - - readonly property var languageNames: [ - tr("System default"), "English", "Magyar", "Deutsch", - "Français", "Español", "Italiano", "Português (Brasil)", - "Русский", "Polski", "Nederlands", "Türkçe", - "日本語", "한국어", "简体中文", "繁體中文" - ] - - Kirigami.FormLayout { - QQC2.ComboBox { - id: languageCombo - Kirigami.FormData.label: tr("Language:") - - model: languageNames - currentIndex: languageValues.indexOf(cfg_language) - - onActivated: index => { - cfg_language = languageValues[index] - } - } - - RowLayout { - Kirigami.FormData.label: tr("Refresh interval:") - - QQC2.SpinBox { - id: refreshSpinBox - from: 1 - to: 999 - stepSize: 1 - value: cfg_refreshInterval - - onValueChanged: { - cfg_refreshInterval = value - } - } - - QQC2.Label { - text: tr("minutes") - } - } - - QQC2.Label { - visible: cfg_refreshInterval < 5 - text: "⚠ " + tr("Values under 5 min may cause rate limiting") - color: Kirigami.Theme.negativeTextColor - font.italic: true - Layout.fillWidth: true - } - - Kirigami.Separator { - Kirigami.FormData.isSection: true - Kirigami.FormData.label: tr("Panel display") - } - - QQC2.ComboBox { - Kirigami.FormData.label: tr("Layout:") - model: [tr("Horizontal"), tr("Vertical")] - currentIndex: cfg_panelLayout === "vertical" ? 1 : 0 - onCurrentIndexChanged: cfg_panelLayout = currentIndex === 1 ? "vertical" : "horizontal" - } - - QQC2.CheckBox { - Kirigami.FormData.label: tr("Icon:") - text: tr("Show Claude icon") - checked: cfg_showIcon - onCheckedChanged: cfg_showIcon = checked - } - - QQC2.ComboBox { - Kirigami.FormData.label: tr("Style:") - model: [tr("Text"), tr("Circular"), tr("Bar")] - currentIndex: cfg_panelStyle === "circular" ? 1 : cfg_panelStyle === "bar" ? 2 : 0 - onCurrentIndexChanged: { - var styles = ["text", "circular", "bar"] - cfg_panelStyle = styles[currentIndex] - } - } - - QQC2.CheckBox { - Kirigami.FormData.label: tr("Show in panel:") - text: tr("Session (5hr)") - checked: cfg_showSession - onCheckedChanged: cfg_showSession = checked - } - - QQC2.CheckBox { - text: tr("Weekly (7day)") - checked: cfg_showWeekly - onCheckedChanged: cfg_showWeekly = checked - } - - QQC2.CheckBox { - text: tr("Sonnet") - checked: cfg_showSonnet - onCheckedChanged: cfg_showSonnet = checked - } - - RowLayout { - Kirigami.FormData.label: tr("Background opacity (desktop):") - - QQC2.Slider { - id: opacitySlider - from: 0.0 - to: 1.0 - stepSize: 0.05 - value: cfg_backgroundOpacity - Layout.preferredWidth: Kirigami.Units.gridUnit * 10 - - onMoved: { - cfg_backgroundOpacity = value - } - } - - QQC2.Label { - text: Math.round(opacitySlider.value * 100) + "%" - Layout.preferredWidth: Kirigami.Units.gridUnit * 2 - } - } - - Kirigami.Separator { - Kirigami.FormData.isSection: true - Kirigami.FormData.label: tr("Custom API (optional)") - } - - QQC2.TextField { - id: baseUrlField - Kirigami.FormData.label: tr("Base URL:") - placeholderText: "https://api.anthropic.com" - text: cfg_baseUrl - onTextChanged: cfg_baseUrl = text - Layout.fillWidth: true - } - - QQC2.Label { - text: tr("Leave empty to use ~/.claude/.credentials.json (default)") - font.italic: true - opacity: 0.7 - Layout.fillWidth: true - } - - QQC2.TextField { - id: apiKeyField - Kirigami.FormData.label: tr("API key:") - placeholderText: "sk-ant-..." - text: cfg_apiKey - echoMode: TextInput.Password - enabled: cfg_baseUrl !== "" - onTextChanged: cfg_apiKey = text - Layout.fillWidth: true - } - } -} diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/ui/main.qml b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/ui/main.qml deleted file mode 100644 index c7470d0..0000000 --- a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/contents/ui/main.qml +++ /dev/null @@ -1,1163 +0,0 @@ -import QtQuick -import QtQuick.Layouts -import org.kde.plasma.plasmoid -import org.kde.plasma.components as PlasmaComponents -import org.kde.kirigami as Kirigami -import org.kde.plasma.plasma5support as Plasma5Support -import org.kde.plasma.core as PlasmaCore - -PlasmoidItem { - id: root - - // Translations - Translations { - id: i18n - currentLanguage: Plasmoid.configuration.language || "system" - } - - property real sessionUsagePercent: 0 - property real weeklyUsagePercent: 0 - property real sonnetWeeklyPercent: 0 - property real opusWeeklyPercent: 0 - property string lastUpdate: "" - property string planName: "" - property string sessionReset: "" - property string weeklyReset: "" - property string errorMsg: "" - property string accessToken: "" - property string apiKey: "" - property string baseUrl: "" - property bool isLoading: false - property var sessionResetTime: null - property var weeklyResetTime: null - property bool hasSonnetData: false - property bool hasOpusData: false - property bool hasTokenError: false - property bool hasRateLimitError: false - property int rateLimitRetryCount: 0 - property int rateLimitRetryMs: 0 // from retry-after header - property double lastFetchTime: 0 - property double lastSuccessTime: 0 - property bool isStale: false - readonly property int minFetchIntervalMs: 55000 // just under 1 minute - // Stale threshold: if rate limited, use retry-after + buffer; otherwise 3x refresh interval - readonly property int staleThresholdMs: root.hasRateLimitError && root.rateLimitRetryMs > 0 - ? root.rateLimitRetryMs + 60000 - : Math.max(Plasmoid.configuration.refreshInterval || 1, 1) * 60000 * 3 - - // Cache writer - saves last successful data to file - Plasma5Support.DataSource { - id: cacheWriter - engine: "executable" - connectedSources: [] - onNewData: function(sourceName, data) { disconnectSource(sourceName) } - } - - // Cache reader - loads cached data on startup - Plasma5Support.DataSource { - id: cacheReader - engine: "executable" - connectedSources: [] - - onNewData: function(sourceName, data) { - var stdout = (data["stdout"] || "").trim() - disconnectSource(sourceName) - if (stdout.length > 10) { - try { - var cache = JSON.parse(stdout) - var age = Date.now() - (cache.timestamp || 0) - if (age < 86400000) { // less than 24 hours old - root.sessionUsagePercent = cache.session || 0 - root.weeklyUsagePercent = cache.weekly || 0 - root.sonnetWeeklyPercent = cache.sonnet || 0 - root.opusWeeklyPercent = cache.opus || 0 - root.hasSonnetData = cache.hasSonnet || false - root.hasOpusData = cache.hasOpus || false - root.planName = cache.plan || "" - root.sessionReset = cache.sessionReset || "" - root.weeklyReset = cache.weeklyReset || "" - root.sessionResetTime = cache.sessionResetTs ? new Date(cache.sessionResetTs) : null - root.weeklyResetTime = cache.weeklyResetTs ? new Date(cache.weeklyResetTs) : null - root.lastSuccessTime = cache.timestamp - root.lastUpdate = Qt.formatTime(new Date(cache.timestamp), "hh:mm:ss") + " *" - root.isStale = age > root.staleThresholdMs - console.log("Claude Usage: Loaded cache, age:", Math.round(age/60000), "min, stale:", root.isStale) - } else { - console.log("Claude Usage: Cache too old, ignoring") - } - } catch (e) { - console.log("Claude Usage: Cache parse error:", e) - } - } - } - } - - function saveCache() { - var cache = { - session: root.sessionUsagePercent, - weekly: root.weeklyUsagePercent, - sonnet: root.sonnetWeeklyPercent, - opus: root.opusWeeklyPercent, - hasSonnet: root.hasSonnetData, - hasOpus: root.hasOpusData, - plan: root.planName, - sessionReset: root.sessionReset, - weeklyReset: root.weeklyReset, - sessionResetTs: root.sessionResetTime ? root.sessionResetTime.getTime() : null, - weeklyResetTs: root.weeklyResetTime ? root.weeklyResetTime.getTime() : null, - timestamp: Date.now() - } - var json = JSON.stringify(cache) - cacheWriter.connectSource("echo '" + json.replace(/'/g, "'\\''") + "' > $HOME/.local/share/claude-usage-cache.json") - } - - // Stale checker - updates isStale flag periodically - Timer { - id: staleTimer - interval: 60000 - running: true - repeat: true - onTriggered: { - if (root.lastSuccessTime > 0) { - root.isStale = (Date.now() - root.lastSuccessTime) > root.staleThresholdMs - } - } - } - - // Token watcher - polls credentials file during rate limit to detect token refresh - Plasma5Support.DataSource { - id: tokenWatcher - engine: "executable" - connectedSources: [] - - onNewData: function(sourceName, data) { - var stdout = (data["stdout"] || "").trim() - disconnectSource(sourceName) - if (stdout.length > 10) { - try { - var creds = JSON.parse(stdout) - var newToken = (creds.claudeAiOauth || {}).accessToken || "" - if (newToken && newToken !== root.accessToken) { - console.log("Claude Usage: New token detected! Resetting rate limit state.") - root.accessToken = newToken - root.hasRateLimitError = false - root.rateLimitRetryCount = 0 - root.lastFetchTime = 0 - fetchUsageFromApi(true) - } - } catch (e) { - console.log("Claude Usage: Token watcher parse error:", e) - } - } - } - } - - Timer { - id: tokenWatchTimer - interval: 30000 // check every 30 seconds - running: root.hasRateLimitError && !root.baseUrl - repeat: true - onTriggered: { - tokenWatcher.connectSource("cat $HOME/.claude/.credentials.json 2>/dev/null") - } - } - - // Data source for reading credentials file - Plasma5Support.DataSource { - id: fileReader - engine: "executable" - connectedSources: [] - - onNewData: function(sourceName, data) { - var stdout = data["stdout"] || "" - disconnectSource(sourceName) - - console.log("Claude Usage: Got credentials, length:", stdout.length) - - if (stdout.length > 10) { - try { - var creds = JSON.parse(stdout) - var oauth = creds.claudeAiOauth || {} - root.accessToken = oauth.accessToken || "" - - // Get plan name from tier - var tier = oauth.rateLimitTier || "default_claude_pro" - var planMap = { - "default_claude_pro": "Pro", - "default_claude_max_5x": "Max 5x", - "default_claude_max_20x": "Max 20x" - } - root.planName = planMap[tier] || tier - - console.log("Claude Usage: Token found, plan:", root.planName) - - if (root.accessToken) { - fetchUsageFromApi() - } else { - root.errorMsg = i18n.tr("Not logged in") - root.isLoading = false - } - } catch (e) { - console.log("Claude Usage: Failed to parse credentials:", e) - root.errorMsg = "Not logged in" - root.isLoading = false - } - } else { - console.log("Claude Usage: No credentials file found") - root.errorMsg = "Not logged in" - root.isLoading = false - } - } - } - - // Data source for detecting Claude Code version - property string claudeVersion: "" - property string userAgent: "claude-code/" + Qt.formatDateTime(new Date(), "yyyy.M.d") - - Plasma5Support.DataSource { - id: versionReader - engine: "executable" - connectedSources: [] - - onNewData: function(sourceName, data) { - var stdout = (data["stdout"] || "").trim() - disconnectSource(sourceName) - // Output format: "2.1.81 (Claude Code)" - var match = stdout.match(/^(\d+\.\d+\.\d+)/) - if (match) { - root.claudeVersion = match[1] - root.userAgent = "claude-code/" + match[1] - console.log("Claude Usage: Detected version:", root.claudeVersion) - } - } - } - - // Data source for launching claude in terminal - Plasma5Support.DataSource { - id: claudeLauncher - engine: "executable" - connectedSources: [] - - onNewData: function(sourceName, data) { - disconnectSource(sourceName) - console.log("Claude Usage: Terminal launched") - } - } - - function loadCredentials() { - root.isLoading = true - root.errorMsg = "" - var configBaseUrl = (Plasmoid.configuration.baseUrl || "").trim() - if (configBaseUrl) { - root.baseUrl = configBaseUrl.replace(/\/$/, "") - root.apiKey = (Plasmoid.configuration.apiKey || "").trim() - root.planName = "API Key" - console.log("Claude Usage: Using configured base URL:", root.baseUrl) - if (root.apiKey) { - fetchUsageFromApi() - } else { - root.errorMsg = "API key not configured" - root.isLoading = false - } - } else { - root.baseUrl = "" - root.apiKey = "" - console.log("Claude Usage: No base URL configured, reading credentials file") - fileReader.connectSource("cat $HOME/.claude/.credentials.json 2>/dev/null") - } - } - - function fetchUsageFromApi(force) { - var now = Date.now() - if (!force && root.lastFetchTime > 0 && (now - root.lastFetchTime) < root.minFetchIntervalMs) { - console.log("Claude Usage: Skipping fetch, too soon since last request") - root.isLoading = false - return - } - root.lastFetchTime = now - - var url = root.baseUrl - ? root.baseUrl + "/api/oauth/usage" - : "https://api.anthropic.com/api/oauth/usage" - - var xhr = new XMLHttpRequest() - xhr.open("GET", url) - xhr.setRequestHeader("Content-Type", "application/json") - xhr.setRequestHeader("User-Agent", root.userAgent) - xhr.setRequestHeader("anthropic-beta", "oauth-2025-04-20") - - if (root.baseUrl) { - // Custom base URL: authenticate with API key - xhr.setRequestHeader("x-api-key", root.apiKey) - } else { - // Default: OAuth token from credentials file - xhr.setRequestHeader("Authorization", "Bearer " + root.accessToken) - } - - xhr.onreadystatechange = function() { - if (xhr.readyState === XMLHttpRequest.DONE) { - root.isLoading = false - - if (xhr.status === 200) { - try { - var data = JSON.parse(xhr.responseText) - - var fiveHour = data.five_hour || {} - var sevenDay = data.seven_day || {} - - root.sessionUsagePercent = fiveHour.utilization || 0 - root.weeklyUsagePercent = sevenDay.utilization || 0 - root.hasSonnetData = !!data.seven_day_sonnet - root.hasOpusData = !!data.seven_day_opus - root.sonnetWeeklyPercent = root.hasSonnetData ? (data.seven_day_sonnet.utilization || 0) : 0 - root.opusWeeklyPercent = root.hasOpusData ? (data.seven_day_opus.utilization || 0) : 0 - - if (fiveHour.resets_at) { - root.sessionResetTime = new Date(fiveHour.resets_at) - root.sessionReset = Qt.formatTime(root.sessionResetTime, "hh:mm") - } - if (sevenDay.resets_at) { - root.weeklyResetTime = new Date(sevenDay.resets_at) - root.weeklyReset = Qt.formatDateTime(root.weeklyResetTime, "MMM d, hh:mm") - } - - root.lastUpdate = Qt.formatTime(new Date(), "hh:mm:ss") - root.lastSuccessTime = Date.now() - root.isStale = false - root.errorMsg = "" - root.hasTokenError = false - root.hasRateLimitError = false - root.rateLimitRetryCount = 0 - root.rateLimitRetryMs = 0 - saveCache() - - console.log("Claude Usage: API success - session:", root.sessionUsagePercent, "weekly:", root.weeklyUsagePercent) - } catch (e) { - console.log("Claude Usage: JSON parse error:", e) - root.errorMsg = "Parse error" - } - } else if (xhr.status === 401) { - if (root.baseUrl) { - root.errorMsg = i18n.tr("Invalid API key") - console.log("Claude Usage: 401 Unauthorized - invalid API key") - } else { - console.log("Claude Usage: 401 Unauthorized - token expired") - root.hasTokenError = true - root.errorMsg = "" - } - } else if (xhr.status === 404) { - root.errorMsg = root.baseUrl - ? i18n.tr("Endpoint not found") - : i18n.tr("API error") + " (404)" - console.log("Claude Usage: 404 Not Found:", url) - } else if (xhr.status === 429) { - var retryAfter = parseInt(xhr.getResponseHeader("retry-after") || "0") - if (retryAfter > 0) { - root.rateLimitRetryMs = retryAfter * 1000 - } - root.rateLimitRetryCount++ - console.log("Claude Usage: 429 Rate limited (retry #" + root.rateLimitRetryCount + ", retry-after: " + retryAfter + "s, waiting: " + root.rateLimitBackoffMs/1000 + "s)") - root.hasRateLimitError = true - root.lastFetchTime = 0 // allow retry timer to work - root.errorMsg = "" - } else { - root.errorMsg = i18n.tr("API error") + " (" + xhr.status + ")" - console.log("Claude Usage: API error:", xhr.status, xhr.statusText) - } - } - } - - xhr.send() - } - - function refresh() { - root.hasTokenError = false - root.hasRateLimitError = false - root.rateLimitRetryCount = 0 - root.rateLimitRetryMs = 0 - loadCredentials() - } - - // Compact representation (panel) - readonly property bool isVerticalLayout: Plasmoid.configuration.panelLayout === "vertical" - - compactRepresentation: Item { - Layout.minimumWidth: usageRow.implicitWidth + Kirigami.Units.largeSpacing * 2 - Layout.minimumHeight: root.isVerticalLayout ? usageRow.implicitHeight + Kirigami.Units.largeSpacing * 2 : Kirigami.Units.iconSizes.medium - Layout.preferredWidth: usageRow.implicitWidth + Kirigami.Units.largeSpacing * 2 - Layout.preferredHeight: root.isVerticalLayout ? usageRow.implicitHeight + Kirigami.Units.largeSpacing * 2 : -1 - - MouseArea { - anchors.fill: parent - onClicked: root.expanded = !root.expanded - } - - GridLayout { - id: usageRow - anchors.centerIn: parent - columns: root.isVerticalLayout ? 1 : -1 - rows: root.isVerticalLayout ? -1 : 1 - flow: root.isVerticalLayout ? GridLayout.TopToBottom : GridLayout.LeftToRight - columnSpacing: Kirigami.Units.smallSpacing - rowSpacing: Kirigami.Units.smallSpacing / 2 - - // Claude icon with error indicator - Item { - visible: Plasmoid.configuration.showIcon !== false - Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium - Layout.preferredHeight: Kirigami.Units.iconSizes.smallMedium - Layout.rightMargin: Kirigami.Units.smallSpacing - - Kirigami.Icon { - anchors.fill: parent - source: Qt.resolvedUrl("../icons/claude.svg") - } - - // Red dot for token/rate limit error - Rectangle { - visible: root.hasTokenError || root.hasRateLimitError - width: 8 - height: 8 - radius: 4 - color: Kirigami.Theme.negativeTextColor - anchors.right: parent.right - anchors.bottom: parent.bottom - anchors.rightMargin: -2 - anchors.bottomMargin: -2 - } - } - - // Error state (non-token errors) - PlasmaComponents.Label { - visible: root.errorMsg !== "" && !root.hasTokenError && !root.hasRateLimitError - text: "⚠" - font.pixelSize: Kirigami.Theme.defaultFont.pixelSize - color: Kirigami.Theme.negativeTextColor - } - - // === TEXT STYLE === - - // Session usage (text) - Rectangle { - visible: (!Plasmoid.configuration.panelStyle || Plasmoid.configuration.panelStyle === "text") && (Plasmoid.configuration.showSession !== false) && (root.errorMsg === "" || root.hasTokenError || root.hasRateLimitError) - Layout.preferredWidth: 10 - Layout.preferredHeight: 10 - radius: 5 - color: getUsageColor(root.sessionUsagePercent) - opacity: (root.hasTokenError || root.hasRateLimitError) ? 0.5 : root.isStale ? 0.6 : 1.0 - } - - PlasmaComponents.Label { - visible: (!Plasmoid.configuration.panelStyle || Plasmoid.configuration.panelStyle === "text") && (Plasmoid.configuration.showSession !== false) && (root.errorMsg === "" || root.hasTokenError || root.hasRateLimitError) - text: Math.round(root.sessionUsagePercent) + "%" - font.pixelSize: Kirigami.Theme.defaultFont.pixelSize - font.bold: true - opacity: (root.hasTokenError || root.hasRateLimitError) ? 0.5 : root.isStale ? 0.6 : 1.0 - } - - // Separator session-weekly (text) - PlasmaComponents.Label { - visible: !root.isVerticalLayout && (!Plasmoid.configuration.panelStyle || Plasmoid.configuration.panelStyle === "text") && (Plasmoid.configuration.showSession !== false) && (Plasmoid.configuration.showWeekly !== false) && (root.errorMsg === "" || root.hasTokenError || root.hasRateLimitError) - text: "|" - opacity: (root.hasTokenError || root.hasRateLimitError) ? 0.25 : root.isStale ? 0.35 : 0.5 - font.pixelSize: Kirigami.Theme.defaultFont.pixelSize - } - - // Weekly usage (text) - Rectangle { - visible: (!Plasmoid.configuration.panelStyle || Plasmoid.configuration.panelStyle === "text") && (Plasmoid.configuration.showWeekly !== false) && (root.errorMsg === "" || root.hasTokenError || root.hasRateLimitError) - Layout.preferredWidth: 10 - Layout.preferredHeight: 10 - radius: 5 - color: getUsageColor(root.weeklyUsagePercent) - opacity: (root.hasTokenError || root.hasRateLimitError) ? 0.5 : root.isStale ? 0.6 : 1.0 - } - - PlasmaComponents.Label { - visible: (!Plasmoid.configuration.panelStyle || Plasmoid.configuration.panelStyle === "text") && (Plasmoid.configuration.showWeekly !== false) && (root.errorMsg === "" || root.hasTokenError || root.hasRateLimitError) - text: Math.round(root.weeklyUsagePercent) + "%" - font.pixelSize: Kirigami.Theme.defaultFont.pixelSize - font.bold: true - opacity: (root.hasTokenError || root.hasRateLimitError) ? 0.5 : root.isStale ? 0.6 : 1.0 - } - - // Separator before sonnet (text) - PlasmaComponents.Label { - visible: !root.isVerticalLayout && (!Plasmoid.configuration.panelStyle || Plasmoid.configuration.panelStyle === "text") && (Plasmoid.configuration.showSonnet === true) && ((Plasmoid.configuration.showSession !== false) || (Plasmoid.configuration.showWeekly !== false)) && (root.errorMsg === "" || root.hasTokenError || root.hasRateLimitError) - text: "|" - opacity: (root.hasTokenError || root.hasRateLimitError) ? 0.25 : root.isStale ? 0.35 : 0.5 - font.pixelSize: Kirigami.Theme.defaultFont.pixelSize - } - - // Sonnet usage (text) - Rectangle { - visible: (!Plasmoid.configuration.panelStyle || Plasmoid.configuration.panelStyle === "text") && (Plasmoid.configuration.showSonnet === true) && (root.errorMsg === "" || root.hasTokenError || root.hasRateLimitError) - Layout.preferredWidth: 10 - Layout.preferredHeight: 10 - radius: 5 - color: getUsageColor(root.sonnetWeeklyPercent) - opacity: (root.hasTokenError || root.hasRateLimitError) ? 0.5 : root.isStale ? 0.6 : 1.0 - } - - PlasmaComponents.Label { - visible: (!Plasmoid.configuration.panelStyle || Plasmoid.configuration.panelStyle === "text") && (Plasmoid.configuration.showSonnet === true) && (root.errorMsg === "" || root.hasTokenError || root.hasRateLimitError) - text: Math.round(root.sonnetWeeklyPercent) + "%" - font.pixelSize: Kirigami.Theme.defaultFont.pixelSize - font.bold: true - opacity: (root.hasTokenError || root.hasRateLimitError) ? 0.5 : root.isStale ? 0.6 : 1.0 - } - - // === CIRCULAR STYLE === - - // Session (circular) - Item { - visible: Plasmoid.configuration.panelStyle === "circular" && (Plasmoid.configuration.showSession !== false) && (root.errorMsg === "" || root.hasTokenError || root.hasRateLimitError) - Layout.preferredWidth: 28 - Layout.preferredHeight: 28 - opacity: (root.hasTokenError || root.hasRateLimitError) ? 0.5 : root.isStale ? 0.6 : 1.0 - - Canvas { - anchors.fill: parent - onPaint: { - var ctx = getContext("2d") - drawCircularProgress(ctx, width, height, root.sessionUsagePercent) - } - property real _percent: root.sessionUsagePercent - on_PercentChanged: requestPaint() - Component.onCompleted: requestPaint() - } - - PlasmaComponents.Label { - anchors.centerIn: parent - text: Math.round(root.sessionUsagePercent) - font.pixelSize: 9 - font.bold: true - } - } - - // Weekly (circular) - Item { - visible: Plasmoid.configuration.panelStyle === "circular" && (Plasmoid.configuration.showWeekly !== false) && (root.errorMsg === "" || root.hasTokenError || root.hasRateLimitError) - Layout.preferredWidth: 28 - Layout.preferredHeight: 28 - opacity: (root.hasTokenError || root.hasRateLimitError) ? 0.5 : root.isStale ? 0.6 : 1.0 - - Canvas { - anchors.fill: parent - onPaint: { - var ctx = getContext("2d") - drawCircularProgress(ctx, width, height, root.weeklyUsagePercent) - } - property real _percent: root.weeklyUsagePercent - on_PercentChanged: requestPaint() - Component.onCompleted: requestPaint() - } - - PlasmaComponents.Label { - anchors.centerIn: parent - text: Math.round(root.weeklyUsagePercent) - font.pixelSize: 9 - font.bold: true - } - } - - // Sonnet (circular) - Item { - visible: Plasmoid.configuration.panelStyle === "circular" && (Plasmoid.configuration.showSonnet === true) && (root.errorMsg === "" || root.hasTokenError || root.hasRateLimitError) - Layout.preferredWidth: 28 - Layout.preferredHeight: 28 - opacity: (root.hasTokenError || root.hasRateLimitError) ? 0.5 : root.isStale ? 0.6 : 1.0 - - Canvas { - anchors.fill: parent - onPaint: { - var ctx = getContext("2d") - drawCircularProgress(ctx, width, height, root.sonnetWeeklyPercent) - } - property real _percent: root.sonnetWeeklyPercent - on_PercentChanged: requestPaint() - Component.onCompleted: requestPaint() - } - - PlasmaComponents.Label { - anchors.centerIn: parent - text: Math.round(root.sonnetWeeklyPercent) - font.pixelSize: 9 - font.bold: true - } - } - - // === BAR STYLE === - - // Session (bar) - Item { - visible: Plasmoid.configuration.panelStyle === "bar" && (Plasmoid.configuration.showSession !== false) && (root.errorMsg === "" || root.hasTokenError || root.hasRateLimitError) - Layout.preferredWidth: 32 - Layout.preferredHeight: parent.height - opacity: (root.hasTokenError || root.hasRateLimitError) ? 0.5 : root.isStale ? 0.6 : 1.0 - - Rectangle { - anchors.fill: parent - radius: 3 - color: Kirigami.Theme.backgroundColor - border.color: Kirigami.Theme.disabledTextColor - border.width: 1 - - Rectangle { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: 1 - height: Math.max((parent.height - 2) * Math.min(root.sessionUsagePercent / 100, 1), 1) - radius: 2 - color: getUsageColor(root.sessionUsagePercent) - } - } - - PlasmaComponents.Label { - anchors.centerIn: parent - text: Math.round(root.sessionUsagePercent) - font.pixelSize: 9 - font.bold: true - } - } - - // Weekly (bar) - Item { - visible: Plasmoid.configuration.panelStyle === "bar" && (Plasmoid.configuration.showWeekly !== false) && (root.errorMsg === "" || root.hasTokenError || root.hasRateLimitError) - Layout.preferredWidth: 32 - Layout.preferredHeight: parent.height - opacity: (root.hasTokenError || root.hasRateLimitError) ? 0.5 : root.isStale ? 0.6 : 1.0 - - Rectangle { - anchors.fill: parent - radius: 3 - color: Kirigami.Theme.backgroundColor - border.color: Kirigami.Theme.disabledTextColor - border.width: 1 - - Rectangle { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: 1 - height: Math.max((parent.height - 2) * Math.min(root.weeklyUsagePercent / 100, 1), 1) - radius: 2 - color: getUsageColor(root.weeklyUsagePercent) - } - } - - PlasmaComponents.Label { - anchors.centerIn: parent - text: Math.round(root.weeklyUsagePercent) - font.pixelSize: 9 - font.bold: true - } - } - - // Sonnet (bar) - Item { - visible: Plasmoid.configuration.panelStyle === "bar" && (Plasmoid.configuration.showSonnet === true) && (root.errorMsg === "" || root.hasTokenError || root.hasRateLimitError) - Layout.preferredWidth: 32 - Layout.preferredHeight: parent.height - opacity: (root.hasTokenError || root.hasRateLimitError) ? 0.5 : root.isStale ? 0.6 : 1.0 - - Rectangle { - anchors.fill: parent - radius: 3 - color: Kirigami.Theme.backgroundColor - border.color: Kirigami.Theme.disabledTextColor - border.width: 1 - - Rectangle { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: 1 - height: Math.max((parent.height - 2) * Math.min(root.sonnetWeeklyPercent / 100, 1), 1) - radius: 2 - color: getUsageColor(root.sonnetWeeklyPercent) - } - } - - PlasmaComponents.Label { - anchors.centerIn: parent - text: Math.round(root.sonnetWeeklyPercent) - font.pixelSize: 9 - font.bold: true - } - } - - // Error text (non-token errors only) - PlasmaComponents.Label { - visible: root.errorMsg !== "" && !root.hasTokenError && !root.hasRateLimitError - text: root.errorMsg - font.pixelSize: Kirigami.Theme.smallFont.pixelSize - color: Kirigami.Theme.negativeTextColor - } - } - } - - // Full representation (popup) - fullRepresentation: Item { - Layout.minimumWidth: Kirigami.Units.gridUnit * 14 - Layout.minimumHeight: Kirigami.Units.gridUnit * 16 - Layout.preferredWidth: Kirigami.Units.gridUnit * 16 - Layout.preferredHeight: Kirigami.Units.gridUnit * 18 - - ColumnLayout { - anchors.fill: parent - anchors.margins: Kirigami.Units.largeSpacing - spacing: Kirigami.Units.mediumSpacing - - // Header - RowLayout { - Layout.fillWidth: true - PlasmaComponents.Label { - text: i18n.tr("Claude Usage") - font.bold: true - font.pixelSize: Kirigami.Theme.defaultFont.pixelSize * 1.3 - } - Item { Layout.fillWidth: true } - Rectangle { - Layout.preferredWidth: planLabel.implicitWidth + Kirigami.Units.smallSpacing * 2 - Layout.preferredHeight: planLabel.implicitHeight + Kirigami.Units.smallSpacing - radius: 3 - color: Kirigami.Theme.highlightColor - PlasmaComponents.Label { - id: planLabel - anchors.centerIn: parent - text: root.planName - font.pixelSize: Kirigami.Theme.smallFont.pixelSize - color: Kirigami.Theme.highlightedTextColor - } - } - } - - // Error message (regular errors) - Rectangle { - visible: root.errorMsg !== "" && !root.hasTokenError && !root.hasRateLimitError - Layout.fillWidth: true - Layout.preferredHeight: errorColumn.implicitHeight + Kirigami.Units.largeSpacing - radius: 5 - color: Kirigami.Theme.negativeBackgroundColor - - ColumnLayout { - id: errorColumn - anchors.fill: parent - anchors.margins: Kirigami.Units.smallSpacing - - PlasmaComponents.Label { - text: "⚠ " + root.errorMsg - color: Kirigami.Theme.negativeTextColor - font.bold: true - } - PlasmaComponents.Label { - text: root.baseUrl - ? i18n.tr("Check base URL and API key in widget settings") - : i18n.tr("Run 'claude' to log in") - font.pixelSize: Kirigami.Theme.smallFont.pixelSize - color: Kirigami.Theme.negativeTextColor - } - } - } - - // Token error message - Rectangle { - visible: root.hasTokenError - Layout.fillWidth: true - Layout.preferredHeight: tokenErrorColumn.implicitHeight + Kirigami.Units.largeSpacing - radius: 5 - color: Kirigami.Theme.negativeBackgroundColor - - ColumnLayout { - id: tokenErrorColumn - anchors.fill: parent - anchors.margins: Kirigami.Units.smallSpacing - spacing: Kirigami.Units.smallSpacing - - PlasmaComponents.Label { - text: "⚠ " + i18n.tr("Token expired") - color: Kirigami.Theme.negativeTextColor - font.bold: true - } - - PlasmaComponents.Button { - text: i18n.tr("Open Claude") - icon.name: "utilities-terminal" - onClicked: { - claudeLauncher.connectSource("bash -c 'cd $HOME && if command -v konsole >/dev/null; then konsole --hold -e env -u CLAUDECODE bash -lc claude; elif command -v gnome-terminal >/dev/null; then gnome-terminal -- env -u CLAUDECODE bash -lc \"claude; exec bash\"; elif command -v xfce4-terminal >/dev/null; then xfce4-terminal --hold -e \"env -u CLAUDECODE bash -lc claude\"; elif command -v xterm >/dev/null; then xterm -hold -e env -u CLAUDECODE bash -lc claude; fi &'") - } - } - } - } - - // Rate limit error message - Rectangle { - visible: root.hasRateLimitError - Layout.fillWidth: true - Layout.preferredHeight: rateLimitErrorColumn.implicitHeight + Kirigami.Units.largeSpacing - radius: 5 - color: Kirigami.Theme.negativeBackgroundColor - - ColumnLayout { - id: rateLimitErrorColumn - anchors.fill: parent - anchors.margins: Kirigami.Units.smallSpacing - spacing: Kirigami.Units.smallSpacing - - PlasmaComponents.Label { - text: "⚠ " + i18n.tr("Rate limited") - color: Kirigami.Theme.negativeTextColor - font.bold: true - } - - PlasmaComponents.Label { - text: i18n.tr("Auto-retry in") + " " + Math.round(root.rateLimitBackoffMs / 60000) + " min" - font.pixelSize: Kirigami.Theme.smallFont.pixelSize - color: Kirigami.Theme.negativeTextColor - } - } - } - - // Separator - Rectangle { - Layout.fillWidth: true - height: 1 - color: Kirigami.Theme.disabledTextColor - opacity: 0.3 - } - - // Session Usage - ColumnLayout { - Layout.fillWidth: true - spacing: Kirigami.Units.smallSpacing - - RowLayout { - Layout.fillWidth: true - PlasmaComponents.Label { - text: i18n.tr("Session (5hr)") - font.bold: true - } - Item { Layout.fillWidth: true } - PlasmaComponents.Label { - text: Math.round(root.sessionUsagePercent) + "%" - color: getUsageColor(root.sessionUsagePercent) - font.bold: true - } - } - - Rectangle { - Layout.fillWidth: true - height: 10 - radius: 5 - color: Kirigami.Theme.backgroundColor - border.color: Kirigami.Theme.disabledTextColor - border.width: 1 - Rectangle { - width: parent.width * Math.min(root.sessionUsagePercent / 100, 1) - height: parent.height - radius: 5 - color: getUsageColor(root.sessionUsagePercent) - } - } - - PlasmaComponents.Label { - visible: root.sessionReset !== "" - text: i18n.tr("Resets at:") + " " + root.sessionReset + (root.sessionResetTime ? " (" + formatTimeRemaining(root.sessionResetTime) + ")" : "") - font.pixelSize: Kirigami.Theme.smallFont.pixelSize - color: Kirigami.Theme.disabledTextColor - } - } - - // Weekly Usage - ColumnLayout { - Layout.fillWidth: true - spacing: Kirigami.Units.smallSpacing - - RowLayout { - Layout.fillWidth: true - PlasmaComponents.Label { - text: i18n.tr("Weekly (7day)") - font.bold: true - } - Item { Layout.fillWidth: true } - PlasmaComponents.Label { - text: Math.round(root.weeklyUsagePercent) + "%" - color: getUsageColor(root.weeklyUsagePercent) - font.bold: true - } - } - - Rectangle { - Layout.fillWidth: true - height: 10 - radius: 5 - color: Kirigami.Theme.backgroundColor - border.color: Kirigami.Theme.disabledTextColor - border.width: 1 - Rectangle { - width: parent.width * Math.min(root.weeklyUsagePercent / 100, 1) - height: parent.height - radius: 5 - color: getUsageColor(root.weeklyUsagePercent) - } - } - - PlasmaComponents.Label { - visible: root.weeklyReset !== "" - text: i18n.tr("Resets:") + " " + root.weeklyReset + (root.weeklyResetTime ? " (" + formatTimeRemaining(root.weeklyResetTime) + ")" : "") - font.pixelSize: Kirigami.Theme.smallFont.pixelSize - color: Kirigami.Theme.disabledTextColor - } - } - - // Separator - Rectangle { - Layout.fillWidth: true - height: 1 - color: Kirigami.Theme.disabledTextColor - opacity: 0.3 - } - - // Model breakdown - PlasmaComponents.Label { - text: i18n.tr("By Model (Weekly)") - font.bold: true - font.pixelSize: Kirigami.Theme.smallFont.pixelSize - } - - // Sonnet - RowLayout { - Layout.fillWidth: true - visible: root.hasSonnetData - - PlasmaComponents.Label { - text: i18n.tr("Sonnet") - } - Item { Layout.fillWidth: true } - Rectangle { - Layout.preferredWidth: 60 - height: 8 - radius: 3 - color: Kirigami.Theme.backgroundColor - border.color: Kirigami.Theme.disabledTextColor - border.width: 1 - Rectangle { - width: parent.width * Math.min(root.sonnetWeeklyPercent / 100, 1) - height: parent.height - radius: 3 - color: getUsageColor(root.sonnetWeeklyPercent) - } - } - PlasmaComponents.Label { - text: Math.round(root.sonnetWeeklyPercent) + "%" - Layout.preferredWidth: 40 - horizontalAlignment: Text.AlignRight - } - } - - // Opus - RowLayout { - Layout.fillWidth: true - visible: root.hasOpusData - - PlasmaComponents.Label { - text: i18n.tr("Opus") - } - Item { Layout.fillWidth: true } - Rectangle { - Layout.preferredWidth: 60 - height: 8 - radius: 3 - color: Kirigami.Theme.backgroundColor - border.color: Kirigami.Theme.disabledTextColor - border.width: 1 - Rectangle { - width: parent.width * Math.min(root.opusWeeklyPercent / 100, 1) - height: parent.height - radius: 3 - color: getUsageColor(root.opusWeeklyPercent) - } - } - PlasmaComponents.Label { - text: Math.round(root.opusWeeklyPercent) + "%" - Layout.preferredWidth: 40 - horizontalAlignment: Text.AlignRight - } - } - - // No model data message - PlasmaComponents.Label { - visible: !root.hasSonnetData && !root.hasOpusData - text: i18n.tr("No model breakdown available") - font.pixelSize: Kirigami.Theme.smallFont.pixelSize - color: Kirigami.Theme.disabledTextColor - font.italic: true - } - - // Rate limit warning - PlasmaComponents.Label { - visible: (Plasmoid.configuration.refreshInterval || 5) < 5 - text: "⚠ " + i18n.tr("Values under 5 min may cause rate limiting") - font.pixelSize: Kirigami.Theme.smallFont.pixelSize - color: Kirigami.Theme.neutralTextColor - font.italic: true - Layout.fillWidth: true - wrapMode: Text.WordWrap - } - - Item { Layout.fillHeight: true } - - // Footer - Rectangle { - Layout.fillWidth: true - height: 1 - color: Kirigami.Theme.disabledTextColor - opacity: 0.3 - } - - RowLayout { - Layout.fillWidth: true - PlasmaComponents.Label { - text: root.lastUpdate !== "" ? i18n.tr("Updated:") + " " + root.lastUpdate : i18n.tr("Loading...") - font.pixelSize: Kirigami.Theme.smallFont.pixelSize - color: Kirigami.Theme.disabledTextColor - } - Item { Layout.fillWidth: true } - PlasmaComponents.Button { - icon.name: "view-refresh" - text: i18n.tr("Refresh") - onClicked: refresh() - } - } - } - } - - Timer { - id: rateLimitRetryTimer - interval: root.rateLimitBackoffMs - running: root.hasRateLimitError - repeat: true - onTriggered: { - console.log("Claude Usage: Backoff retry, interval:", interval/1000, "s") - loadCredentials() - } - } - - // Use retry-after header if available, otherwise fallback to 5min steps (capped at 15min) - readonly property int rateLimitBackoffMs: root.rateLimitRetryMs > 0 - ? root.rateLimitRetryMs + 10000 // retry-after + 10s buffer - : Math.min((root.rateLimitRetryCount + 1) * 300000, 900000) - - Timer { - id: refreshTimer - interval: Math.max(Plasmoid.configuration.refreshInterval || 5, 1) * 60000 - running: !root.hasRateLimitError - repeat: true - onTriggered: loadCredentials() - } - - function drawCircularProgress(ctx, w, h, percent) { - var centerX = w / 2 - var centerY = h / 2 - var radius = Math.min(w, h) / 2 - 2 - var lineWidth = 3 - var startAngle = -Math.PI / 2 - var endAngle = startAngle + (2 * Math.PI * Math.min(percent, 100) / 100) - - ctx.reset() - - // Background circle - ctx.beginPath() - ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI) - ctx.strokeStyle = Kirigami.Theme.disabledTextColor - ctx.globalAlpha = 0.3 - ctx.lineWidth = lineWidth - ctx.stroke() - - // Progress arc - if (percent > 0) { - ctx.beginPath() - ctx.arc(centerX, centerY, radius, startAngle, endAngle) - ctx.strokeStyle = getUsageColor(percent) - ctx.globalAlpha = 1.0 - ctx.lineWidth = lineWidth - ctx.lineCap = "round" - ctx.stroke() - } - } - - function getUsageColor(percent) { - if (percent < 50) return Kirigami.Theme.positiveTextColor - if (percent < 80) return Kirigami.Theme.neutralTextColor - return Kirigami.Theme.negativeTextColor - } - - function formatTimeRemaining(resetTime) { - if (!resetTime) return "" - var now = new Date() - var diff = resetTime.getTime() - now.getTime() - if (diff <= 0) return "" - - var hours = Math.floor(diff / (1000 * 60 * 60)) - var minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)) - - if (hours > 24) { - var days = Math.floor(hours / 24) - hours = hours % 24 - return days + i18n.tr("d") + " " + hours + i18n.tr("h") - } else if (hours > 0) { - return hours + i18n.tr("h") + " " + minutes + i18n.tr("m") - } else { - return minutes + i18n.tr("m") - } - } - - // Install icon to system theme for about page - Plasma5Support.DataSource { - id: iconInstaller - engine: "executable" - connectedSources: [] - onNewData: function(sourceName, data) { disconnectSource(sourceName) } - } - - Component.onCompleted: { - console.log("Claude Usage: Widget loaded") - var iconSource = Qt.resolvedUrl("../icons/claude-usage-widget.svg").toString().replace("file://", "") - iconInstaller.connectSource("bash -c 'ICON_DIR=${XDG_DATA_HOME:-$HOME/.local/share}/icons/hicolor/scalable/apps && mkdir -p $ICON_DIR && cp \"" + iconSource + "\" $ICON_DIR/claude-usage-widget.svg && chmod 644 $ICON_DIR/claude-usage-widget.svg 2>/dev/null'") - cacheReader.connectSource("cat $HOME/.local/share/claude-usage-cache.json 2>/dev/null") - versionReader.connectSource("claude --version 2>/dev/null") - loadCredentials() - } - - // Only use custom background on desktop, panel keeps default Plasma background - readonly property bool isOnPanel: Plasmoid.location === PlasmaCore.Types.TopEdge - || Plasmoid.location === PlasmaCore.Types.BottomEdge - || Plasmoid.location === PlasmaCore.Types.LeftEdge - || Plasmoid.location === PlasmaCore.Types.RightEdge - - Plasmoid.backgroundHints: isOnPanel ? PlasmaCore.Types.DefaultBackground : PlasmaCore.Types.NoBackground - - // Custom background with configurable opacity (desktop only) - Rectangle { - visible: !root.isOnPanel - anchors.fill: parent - color: Kirigami.Theme.backgroundColor - opacity: Plasmoid.configuration.backgroundOpacity - radius: Kirigami.Units.cornerRadius - } - - Plasmoid.icon: "claude-usage-widget" - toolTipMainText: i18n.tr("Claude Usage") - toolTipSubText: { - var parts = [] - if (Plasmoid.configuration.showSession !== false) - parts.push(i18n.tr("Session (5hr)") + ": " + Math.round(root.sessionUsagePercent) + "%") - if (Plasmoid.configuration.showWeekly !== false) - parts.push(i18n.tr("Weekly (7day)") + ": " + Math.round(root.weeklyUsagePercent) + "%") - if (Plasmoid.configuration.showSonnet === true) - parts.push(i18n.tr("Sonnet") + ": " + Math.round(root.sonnetWeeklyPercent) + "%") - return parts.join(" | ") - } -} diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/executable_install.sh b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/executable_install.sh deleted file mode 100644 index 27f137c..0000000 --- a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/executable_install.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -PLUGIN_ID="org.kde.plasma.claudeusage" -INSTALL_DIR="$HOME/.local/share/plasma/plasmoids/$PLUGIN_ID" -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" - -echo "Installing Claude Usage widget..." - -mkdir -p "$INSTALL_DIR" -cp -r "$SCRIPT_DIR/contents" "$INSTALL_DIR/" -cp "$SCRIPT_DIR/metadata.json" "$INSTALL_DIR/" - -echo "Installed to $INSTALL_DIR" -echo "" -echo "Restart Plasma to apply changes:" -echo " kquitapp6 plasmashell && kstart plasmashell" diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/logo.png b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/logo.png deleted file mode 100644 index 8e6d0a2..0000000 Binary files a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/logo.png and /dev/null differ diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/logo.svg b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/logo.svg deleted file mode 100644 index c351cf2..0000000 --- a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/logo.svg +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - USAGE - diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/metadata.json b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/metadata.json deleted file mode 100644 index 966811f..0000000 --- a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/metadata.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "KPackageStructure": "Plasma/Applet", - "KPlugin": { - "Authors": [ - { - "Name": "izll" - } - ], - "Category": "System Information", - "Description": "Display Claude Code usage statistics (session and weekly limits) in your taskbar. Shows real-time usage percentages with color-coded indicators.", - "EnabledByDefault": true, - "Icon": "claude-usage-widget", - "Id": "org.kde.plasma.claudeusageswitcher", - "License": "GPL-3.0-or-later", - "Name": "Claude Usage", - "Version": "1.3.6", - "Website": "https://github.com/izll/plasma-claude-usage" - }, - "X-Plasma-API-Minimum-Version": "6.0", - "X-Plasma-Provides": [] -} diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/screenshots/panel.png b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/screenshots/panel.png deleted file mode 100644 index 4ab282e..0000000 Binary files a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/screenshots/panel.png and /dev/null differ diff --git a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/screenshots/popup.png b/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/screenshots/popup.png deleted file mode 100644 index 4c51c95..0000000 Binary files a/dot_local/share/plasma/plasmoids/org.kde.plasma.claudeusageswitcher/screenshots/popup.png and /dev/null differ diff --git a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/config/config.qml b/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/config/config.qml deleted file mode 100644 index 5f6eaa4..0000000 --- a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/config/config.qml +++ /dev/null @@ -1,17 +0,0 @@ -/* - SPDX-FileCopyrightText: 2014 Eike Hein - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -import QtQuick 2.15 - -import org.kde.plasma.configuration 2.0 - -ConfigModel { - ConfigCategory { - name: i18n("General") - icon: "preferences-desktop-plasma" - source: "ConfigGeneral.qml" - } -} diff --git a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/config/main.xml b/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/config/main.xml deleted file mode 100644 index f1d976b..0000000 --- a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/config/main.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - start-here-kde-symbolic - - - - false - - - - - - - - - 0 - - - - false - - - - false - - - - - 0 - - - - preferred://browser,org.kde.kontact.desktop,systemsettings.desktop,org.kde.dolphin.desktop,org.kde.discover - - - - shutdown,reboot,logout,lock-screen - - - - false - - - - - - - - - true - - - - true - - - - - true - - - - krunner_shell,krunner_bookmarksrunner,baloosearch,locations - - - - true - - - - false - - - - 3 - - - - 2 - - - - 1 - - - - diff --git a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ActionMenu.qml b/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ActionMenu.qml deleted file mode 100644 index be10f70..0000000 --- a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ActionMenu.qml +++ /dev/null @@ -1,122 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013 Aurélien Gâteau - SPDX-FileCopyrightText: 2014-2015 Eike Hein - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -import QtQuick 2.15 - -import org.kde.plasma.extras 2.0 as PlasmaExtras - -Item { - id: root - - property QtObject menu - property Item visualParent - property variant actionList - property bool opened: menu ? (menu.status !== PlasmaExtras.Menu.Closed) : false - - signal actionClicked(string actionId, variant actionArgument) - signal closed - - onActionListChanged: refreshMenu(); - - onOpenedChanged: { - if (!opened) { - closed(); - } - } - - function open(x, y) { - if (!actionList) { - return; - } - - if (x && y) { - menu.open(x, y); - } else { - menu.open(); - } - } - - function refreshMenu() { - if (menu) { - menu.destroy(); - } - - if (!actionList) { - return; - } - - menu = contextMenuComponent.createObject(root); - - fillMenu(menu, actionList); - } - - function fillMenu(menu, items) { - items.forEach(function(actionItem) { - if (actionItem.subActions) { - // This is a menu - var submenuItem = contextSubmenuItemComponent.createObject( - menu, { "actionItem" : actionItem }); - - fillMenu(submenuItem.submenu, actionItem.subActions); - - } else { - var item = contextMenuItemComponent.createObject( - menu, - { - "actionItem": actionItem, - } - ); - } - }); - - } - - Component { - id: contextMenuComponent - - PlasmaExtras.Menu { - visualParent: root.visualParent - } - } - - Component { - id: contextSubmenuItemComponent - - PlasmaExtras.MenuItem { - id: submenuItem - - property variant actionItem - - text: actionItem.text ? actionItem.text : "" - icon: actionItem.icon ? actionItem.icon : null - - property PlasmaExtras.Menu submenu: PlasmaExtras.Menu { - visualParent: submenuItem.action - } - } - } - - Component { - id: contextMenuItemComponent - - PlasmaExtras.MenuItem { - property variant actionItem - - text : actionItem.text ? actionItem.text : "" - enabled : actionItem.type !== "title" && ("enabled" in actionItem ? actionItem.enabled : true) - separator : actionItem.type === "separator" - section : actionItem.type === "title" - icon : actionItem.icon ? actionItem.icon : null - checkable : actionItem.checkable ? actionItem.checkable : false - checked : actionItem.checked ? actionItem.checked : false - - onClicked: { - root.actionClicked(actionItem.actionId, actionItem.actionArgument); - } - } - } -} diff --git a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/CompactRepresentation.qml b/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/CompactRepresentation.qml deleted file mode 100644 index 9b94640..0000000 --- a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/CompactRepresentation.qml +++ /dev/null @@ -1,119 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013-2014 Eike Hein - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -import QtQuick 2.15 -import QtQuick.Layouts 1.15 - -import org.kde.plasma.core as PlasmaCore -import org.kde.plasma.plasmoid 2.0 -import org.kde.kirigami 2.20 as Kirigami - -import org.kde.plasma.private.kicker 0.1 as Kicker - -Item { - id: root - - readonly property bool vertical: (Plasmoid.formFactor === PlasmaCore.Types.Vertical) - readonly property bool useCustomButtonImage: (Plasmoid.configuration.useCustomButtonImage - && Plasmoid.configuration.customButtonImage.length !== 0) - - readonly property Component dashWindowComponent: kicker.isDash ? Qt.createComponent(Qt.resolvedUrl("./DashboardRepresentation.qml"), root) : null - readonly property Kicker.DashboardWindow dashWindow: dashWindowComponent && dashWindowComponent.status === Component.Ready - ? dashWindowComponent.createObject(root, { visualParent: root }) : null - - onWidthChanged: updateSizeHints() - onHeightChanged: updateSizeHints() - - function updateSizeHints() { - if (useCustomButtonImage) { - if (vertical) { - const scaledHeight = Math.floor(parent.width * (buttonIcon.implicitHeight / buttonIcon.implicitWidth)); - root.Layout.minimumWidth = -1; - root.Layout.minimumHeight = scaledHeight; - root.Layout.maximumWidth = Kirigami.Units.iconSizes.huge; - root.Layout.maximumHeight = scaledHeight; - } else { - const scaledWidth = Math.floor(parent.height * (buttonIcon.implicitWidth / buttonIcon.implicitHeight)); - root.Layout.minimumWidth = scaledWidth; - root.Layout.minimumHeight = -1; - root.Layout.maximumWidth = scaledWidth; - root.Layout.maximumHeight = Kirigami.Units.iconSizes.huge; - } - } else { - root.Layout.minimumWidth = Kirigami.Units.iconSizes.huge; - root.Layout.minimumHeight = Kirigami.Units.iconSizes.huge; - } - } - - Kirigami.Icon { - id: buttonIcon - - anchors.fill: parent - - readonly property double aspectRatio: root.vertical - ? implicitHeight / implicitWidth - : implicitWidth / implicitHeight - - active: mouseArea.containsMouse && !justOpenedTimer.running - source: root.useCustomButtonImage ? Plasmoid.configuration.customButtonImage : Plasmoid.configuration.icon - - // A custom icon could also be rectangular. However, if a square, custom, icon is given, assume it - // to be an icon and round it to the nearest icon size again to avoid scaling artifacts. - roundToIconSize: !root.useCustomButtonImage || aspectRatio === 1 - - onSourceChanged: root.updateSizeHints() - } - - MouseArea { - id: mouseArea - - anchors.fill: parent - - property bool wasExpanded: false; - - activeFocusOnTab: true - hoverEnabled: !root.dashWindow || !root.dashWindow.visible - - Keys.onPressed: { - switch (event.key) { - case Qt.Key_Space: - case Qt.Key_Enter: - case Qt.Key_Return: - case Qt.Key_Select: - Plasmoid.activated(); - break; - } - } - Accessible.name: Plasmoid.title - Accessible.description: toolTipSubText - Accessible.role: Accessible.Button - - onPressed: { - if (!kicker.isDash) { - wasExpanded = kicker.expanded - } - } - - onClicked: { - if (kicker.isDash) { - root.dashWindow.toggle(); - justOpenedTimer.start(); - } else { - kicker.expanded = !wasExpanded; - } - } - } - - Connections { - target: Plasmoid - enabled: kicker.isDash && root.dashWindow !== null - - function onActivated() { - root.dashWindow.toggle(); - justOpenedTimer.start(); - } - } -} diff --git a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ConfigGeneral.qml b/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ConfigGeneral.qml deleted file mode 100644 index ff6a529..0000000 --- a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ConfigGeneral.qml +++ /dev/null @@ -1,239 +0,0 @@ -/* - SPDX-FileCopyrightText: 2014 Eike Hein - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -import QtQuick 2.15 -import QtQuick.Controls 2.15 - -import org.kde.draganddrop 2.0 as DragDrop -import org.kde.kirigami 2.5 as Kirigami -import org.kde.iconthemes as KIconThemes -import org.kde.plasma.core as PlasmaCore -import org.kde.kirigami 2.20 as Kirigami -import org.kde.ksvg 1.0 as KSvg -import org.kde.plasma.plasmoid 2.0 -import org.kde.kcmutils as KCM - -KCM.SimpleKCM { - id: configGeneral - - property bool isDash: (Plasmoid.pluginName === "org.kde.plasma.kickerdash") - - property string cfg_icon: Plasmoid.configuration.icon - property bool cfg_useCustomButtonImage: Plasmoid.configuration.useCustomButtonImage - property string cfg_customButtonImage: Plasmoid.configuration.customButtonImage - - property alias cfg_appNameFormat: appNameFormat.currentIndex - property alias cfg_limitDepth: limitDepth.checked - property alias cfg_alphaSort: alphaSort.checked - property alias cfg_showIconsRootLevel: showIconsRootLevel.checked - - property alias cfg_recentOrdering: recentOrdering.currentIndex - property alias cfg_showRecentApps: showRecentApps.checked - property alias cfg_showRecentDocs: showRecentDocs.checked - - property alias cfg_useExtraRunners: useExtraRunners.checked - property alias cfg_alignResultsToBottom: alignResultsToBottom.checked - - property alias cfg_appsIconSize: appsIconSize.currentIndex - property alias cfg_favsIconSize: favsIconSize.currentIndex - property alias cfg_systemIconSize: systemIconSize.currentIndex - - Kirigami.FormLayout { - anchors.left: parent.left - anchors.right: parent.right - - Button { - id: iconButton - - Kirigami.FormData.label: i18n("Icon:") - - implicitWidth: previewFrame.width + Kirigami.Units.smallSpacing * 2 - implicitHeight: previewFrame.height + Kirigami.Units.smallSpacing * 2 - - // Just to provide some visual feedback when dragging; - // cannot have checked without checkable enabled - checkable: true - checked: dropArea.containsAcceptableDrag - - onPressed: iconMenu.opened ? iconMenu.close() : iconMenu.open() - - DragDrop.DropArea { - id: dropArea - - property bool containsAcceptableDrag: false - - anchors.fill: parent - - onDragEnter: { - // Cannot use string operations (e.g. indexOf()) on "url" basic type. - var urlString = event.mimeData.url.toString(); - - // This list is also hardcoded in KIconDialog. - var extensions = [".png", ".xpm", ".svg", ".svgz"]; - containsAcceptableDrag = urlString.indexOf("file:///") === 0 && extensions.some(function (extension) { - return urlString.indexOf(extension) === urlString.length - extension.length; // "endsWith" - }); - - if (!containsAcceptableDrag) { - event.ignore(); - } - } - onDragLeave: containsAcceptableDrag = false - - onDrop: { - if (containsAcceptableDrag) { - // Strip file:// prefix, we already verified in onDragEnter that we have only local URLs. - iconDialog.setCustomButtonImage(event.mimeData.url.toString().substr("file://".length)); - } - containsAcceptableDrag = false; - } - } - - KIconThemes.IconDialog { - id: iconDialog - - function setCustomButtonImage(image) { - configGeneral.cfg_customButtonImage = image || configGeneral.cfg_icon || "start-here-kde-symbolic" - configGeneral.cfg_useCustomButtonImage = true; - } - - onIconNameChanged: setCustomButtonImage(iconName); - } - - KSvg.FrameSvgItem { - id: previewFrame - anchors.centerIn: parent - imagePath: Plasmoid.location === PlasmaCore.Types.Vertical || Plasmoid.location === PlasmaCore.Types.Horizontal - ? "widgets/panel-background" : "widgets/background" - width: Kirigami.Units.iconSizes.large + fixedMargins.left + fixedMargins.right - height: Kirigami.Units.iconSizes.large + fixedMargins.top + fixedMargins.bottom - - Kirigami.Icon { - anchors.centerIn: parent - width: Kirigami.Units.iconSizes.large - height: width - source: configGeneral.cfg_useCustomButtonImage ? configGeneral.cfg_customButtonImage : configGeneral.cfg_icon - } - } - - Menu { - id: iconMenu - - // Appear below the button - y: +parent.height - - onClosed: iconButton.checked = false; - - MenuItem { - text: i18nc("@item:inmenu Open icon chooser dialog", "Choose…") - icon.name: "document-open-folder" - onClicked: iconDialog.open() - } - MenuItem { - text: i18nc("@item:inmenu Reset icon to default", "Clear Icon") - icon.name: "edit-clear" - onClicked: { - configGeneral.cfg_icon = "start-here-kde-symbolic" - configGeneral.cfg_useCustomButtonImage = false - } - } - } - } - - - Item { - Kirigami.FormData.isSection: true - } - - ComboBox { - id: appNameFormat - - Kirigami.FormData.label: i18n("Show applications as:") - - model: [i18n("Name only"), i18n("Description only"), i18n("Name (Description)"), i18n("Description (Name)")] - } - - Item { - Kirigami.FormData.isSection: true - } - - CheckBox { - id: alphaSort - visible: false - Kirigami.FormData.label: i18n("Behavior:") - - text: i18n("Sort applications alphabetically") - } - - CheckBox { - id: limitDepth - visible: false - text: i18n("Flatten sub-menus to a single level") - } - - CheckBox { - id: showIconsRootLevel - visible: false - text: i18n("Show icons on the root level of the menu") - } - - CheckBox { - id: showRecentApps - visible: false - Kirigami.FormData.label: i18n("Show categories:") - - text: recentOrdering.currentIndex == 0 - ? i18n("Recent applications") - : i18n("Often used applications") - } - - CheckBox { - id: showRecentDocs - visible: false - text: recentOrdering.currentIndex == 0 - ? i18n("Recent files") - : i18n("Often used files") - } - - ComboBox { - id: recentOrdering - visible: false - Kirigami.FormData.label: i18n("Sort items in categories by:") - model: [i18nc("@item:inlistbox Sort items in categories by [Recently used | Often used]", "Recently used"), i18nc("@item:inlistbox Sort items in categories by [Recently used | Ofetn used]", "Often used")] - } - - CheckBox { - id: useExtraRunners - visible: false - Kirigami.FormData.label: i18n("Search:") - text: i18n("Expand search to bookmarks, files and emails") - } - - CheckBox { - id: alignResultsToBottom - visible: false - text: i18n("Align search results to bottom") - } - - ComboBox { - id: appsIconSize - Kirigami.FormData.label: i18n("Apps icon size:") - model: [i18n("Small"),i18n("Medium"),i18n("Large"), i18n("Huge"),i18n("HUGE"),i18n("Enormous")] - } - - ComboBox { - id: favsIconSize - Kirigami.FormData.label: i18n("Favs icon size:") - model: [i18n("Small"),i18n("Medium"),i18n("Large"), i18n("Huge"),i18n("Enormous")] - } - - ComboBox { - id: systemIconSize - Kirigami.FormData.label: i18n("Favs icon size:") - model: [i18n("Small"),i18n("Medium"),i18n("Large"), i18n("Huge"),i18n("Enormous")] - } - } -} diff --git a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/DashboardRepresentation.qml b/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/DashboardRepresentation.qml deleted file mode 100644 index c72b6fb..0000000 --- a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/DashboardRepresentation.qml +++ /dev/null @@ -1,523 +0,0 @@ -/* - SPDX-FileCopyrightText: 2015 Eike Hein - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -import QtQuick 2.15 -import Qt5Compat.GraphicalEffects -// Deliberately imported after QtQuick to avoid missing restoreMode property in Binding. Fix in Qt 6. -import QtQml 2.15 - -import org.kde.kquickcontrolsaddons 2.0 -import org.kde.kwindowsystem 1.0 -import org.kde.plasma.components as PlasmaComponents -import org.kde.plasma.extras 2.0 as PlasmaExtras -import org.kde.plasma.core as PlasmaCore -import org.kde.ksvg 1.0 as KSvg -import org.kde.plasma.private.shell 2.0 -import org.kde.kirigami 2.20 as Kirigami -import QtQuick.Layouts 1.1 - -import org.kde.plasma.plasmoid 2.0 -import org.kde.plasma.private.kicker 0.1 as Kicker - -import QtQuick.Controls -import QtQuick -import Qt5Compat.GraphicalEffects - - -import "code/tools.js" as Tools - - -Kicker.DashboardWindow { - id: root - - property bool smallScreen: ((Math.floor(width / Kirigami.Units.iconSizes.huge) <= 22) || (Math.floor(height / Kirigami.Units.iconSizes.huge) <= 14)) - - property int iconSize:{ switch(Plasmoid.configuration.appsIconSize){ - case 0: return Kirigami.Units.iconSizes.smallMedium; - case 1: return Kirigami.Units.iconSizes.medium; - case 2: return Kirigami.Units.iconSizes.large; - case 3: return Kirigami.Units.iconSizes.huge; - case 4: return Kirigami.Units.iconSizes.large * 2; - case 5: return Kirigami.Units.iconSizes.enormous; - default: return 64 - } - } - - property int favsIconSize:{ switch(Plasmoid.configuration.favsIconSize){ - case 0: return Kirigami.Units.iconSizes.smallMedium; - case 1: return Kirigami.Units.iconSizes.medium; - case 2: return Kirigami.Units.iconSizes.large; - case 3: return Kirigami.Units.iconSizes.huge; - case 4: return Kirigami.Units.iconSizes.enormous; - default: return 64 - } - } - - property int systemIconSize:{ switch(Plasmoid.configuration.systemIconSize){ - case 0: return Kirigami.Units.iconSizes.smallMedium; - case 1: return Kirigami.Units.iconSizes.medium; - case 2: return Kirigami.Units.iconSizes.large; - case 3: return Kirigami.Units.iconSizes.huge; - case 4: return Kirigami.Units.iconSizes.enormous; - default: return 64 - } - } - - property int cellSize: iconSize + (2 * Kirigami.Units.iconSizes.sizeForLabels) - + (2 * Kirigami.Units.largeSpacing) - + (2 * Math.max(highlightItemSvg.margins.top + highlightItemSvg.margins.bottom, - highlightItemSvg.margins.left + highlightItemSvg.margins.right)) - //property int columns: Math.floor(width*0.7/root.cellSize)// Math.floor(((smallScreen ? 85 : 80)/100) * Math.ceil(width / cellSize)) - property int columns: Math.floor(((smallScreen ? 85 : 80)/100) * Math.ceil(width / cellSize)) - property bool searching: searchField.text !== "" - - property int favoritesRows: Math.floor(height*0.4/cellSize) - - //keyEventProxy: searchField - backgroundColor: "transparent" - - - onKeyEscapePressed: { - if (searching) { - searchField.clear(); - } else { - root.toggle(); - } - } - - onVisibleChanged: { - if(visible){ - animatorMainColumn.start() - }else{ - rootItem.opacity = 0 - } - reset(); - } - - onSearchingChanged: { - if (!searching) { - //mainView.currentIndex = 1 - mainView.pop() - reset(); - } else { - mainView.push(runnerComponent) - //mainView.currentIndex = 0 - } - } - - function colorWithAlpha(color: color, alpha: real): color { - return Qt.rgba(color.r, color.g, color.b, alpha) - } - - - - function reset() { - allAppsGrid.model = rootModel.modelForRow(2) - globalFavoritesGrid.model = globalFavorites - - allAppsGrid.currentIndex = -1 - globalFavoritesGrid.currentIndex = -1; - systemFavoritesGrid.currentIndex = -1; - - allAppsGrid.forceLayout() - - searchField.clear(); - searchField.focus = true - - } - - mainItem: MouseArea { - id: rootItem - - anchors.fill: parent - - acceptedButtons: Qt.LeftButton | Qt.RightButton - - LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft - LayoutMirroring.childrenInherit: true - - Rectangle{ - anchors.fill: parent - color: Kirigami.Theme.backgroundColor - opacity: 0.4 - } - - - Connections { - target: kicker - - function onReset() { - if (!root.searching) { - //filterList.applyFilter(); - //funnelModel.reset(); - } - } - - function onDragSourceChanged() { - if (!kicker.dragSource) { - // FIXME TODO HACK: Reset all views post-DND to work around - // mouse grab bug despite QQuickWindow::mouseGrabberItem==0x0. - // Needs a more involved hunt through Qt Quick sources later since - // it's not happening with near-identical code in the menu repr. - rootModel.refresh(); - } - } - } - - Connections { - target: Plasmoid - function onUserConfiguringChanged() { - if (Plasmoid.userConfiguring) { - root.hide() - } - } - } - - PlasmaExtras.Menu { - id: contextMenu - - PlasmaExtras.MenuItem { - action: Plasmoid.internalAction("configure") - } - } - - Kirigami.Heading { - id: dummyHeading - - visible: false - - width: 0 - - level: 1 - } - - TextMetrics { - id: headingMetrics - - font: dummyHeading.font - } - - Kicker.FunnelModel { - id: funnelModel - - onSourceModelChanged: { - if (mainColumn.visible) { - mainGrid.currentIndex = -1; - mainGrid.forceLayout(); - } - } - } - - Kicker.ContainmentInterface { - id: containmentInterface - } - - TextField{ - id: searchField - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: mainView.top - anchors.bottomMargin: Kirigami.Units.largeSpacing * 6 - //focus: true - width: Kirigami.Units.gridUnit * 13 - topPadding: Kirigami.Units.largeSpacing - bottomPadding: Kirigami.Units.largeSpacing - placeholderText: i18nc("@info:placeholder as in, 'start typing to initiate a search'", "Search") - horizontalAlignment: TextInput.AlignHCenter - wrapMode: Text.NoWrap - font.pointSize: Kirigami.Theme.defaultFont.pointSize + 0.5 - - onTextChanged: { - runnerModel.query = searchField.text; - } - - function clear() { - text = ""; - } - - background: Rectangle { - color: colorWithAlpha(Kirigami.Theme.backgroundColor,0.7) - radius: 100 - border.width: 1 - border.color: colorWithAlpha(Kirigami.Theme.textColor,0.05) - } - - function appendText(newText) { - if (!root.visible) { - return; - } - focus = true; - text = text + newText; - } - - function backspace() { - if (!root.visible) { - return; - } - focus = true; - text = text.slice(0, -1); - } - - function updateSelection() { - if (!searchField.selectedText) { - return; - } - - var delta = text.lastIndexOf(searchField.text, text.length - 2); - searchHeading.select(searchField.selectionStart + delta, searchField.selectionEnd + delta); - } - Keys.onPressed: event => { - if (event.key === Qt.Key_Down || event.key === Qt.Key_Tab) { - event.accepted = true; - if(root.searching){ - mainView.currentItem.tryActivate(0,0) - mainView.currentItem.forceActiveFocus() - } - else{ - allAppsGrid.tryActivate(0,0) - allAppsGrid.forceActiveFocus() - } - } - } - } - - - OpacityAnimator{ id: animatorMainColumn ;from: 0; to: 1 ; target: rootItem;} - - StackView { - id: mainView - width: (root.columns * root.cellSize) + Kirigami.Units.gridUnit - height: Math.ceil(root.height*0.7/root.cellSize) * root.cellSize - anchors{ - horizontalCenter: parent.horizontalCenter - verticalCenter: parent.verticalCenter - } - - initialItem: Column { - id: allAppsColumn - clip: true - spacing: Kirigami.Units.largeSpacing * 2 - - ItemGridView { - id: allAppsGrid - width: parent.width - height: Math.ceil(root.height*0.7/cellHeight) * cellHeight - cellWidth: root.cellSize - cellHeight: root.cellSize - iconSize: root.iconSize - dropEnabled: false - - onKeyNavDown: { - allAppsGrid.focus = false - globalFavoritesGrid.tryActivate(0,0) - globalFavoritesGrid.forceActiveFocus() - } - onKeyNavUp: { - allAppsGrid.focus = false - searchField.focus = true - } - Keys.onPressed: event => { - if (event.key === Qt.Key_Tab) { - event.accepted = true; - allAppsGrid.focus = false - globalFavoritesGrid.tryActivate(0,0) - globalFavoritesGrid.forceActiveFocus() - } - } - } - } - - pushEnter: Transition { - PropertyAnimation { - property: "opacity" - from: 0 - to:1 - duration: 200 - } - } - pushExit: Transition { - PropertyAnimation { - property: "opacity" - from: 1 - to:0 - duration: 200 - } - } - popEnter: Transition { - PropertyAnimation { - property: "opacity" - from: 0 - to:1 - duration: 200 - } - } - popExit: Transition { - PropertyAnimation { - property: "opacity" - from: 1 - to:0 - duration: 200 - } - } - - } - - Component { - id: runnerComponent - - ItemGridView { - id: runnerGrid - anchors.horizontalCenter: mainView.horizontalCenter - width: mainView.width/2 - clip: true - height: mainView.height - grabFocus: true - cellWidth: root.cellSize - cellHeight: root.cellSize - iconSize: root.iconSize - model: runnerModel.count > 0 ? runnerModel.modelForRow(0) : undefined - onKeyNavDown: { - runnerGrid.focus = false - globalFavoritesGrid.tryActivate(0,0) - globalFavoritesGrid.forceActiveFocus() - } - onKeyNavUp: { - runnerGrid.focus = false - searchField.focus = true - } - Keys.onPressed: event => { - if (event.key === Qt.Key_Tab) { - event.accepted = true; - runnerGrid.focus = false - globalFavoritesGrid.tryActivate(0,0) - globalFavoritesGrid.forceActiveFocus() - } - } - } - - } - - Rectangle{ - anchors.centerIn: globalFavoritesGrid - height: globalFavoritesGrid.height + Kirigami.Units.largeSpacing - width: globalFavoritesGrid.width + Kirigami.Units.largeSpacing - color: Kirigami.Theme.backgroundColor - radius: 10 - opacity: 0.6 - z:1 - } - - ItemGridView { - id: globalFavoritesGrid - width: globalFavoritesGrid.model ? Math.min(Math.floor((root.width*0.85)/cellWidth)*cellWidth,globalFavoritesGrid.model.count*cellWidth) : 0 - - iconSize: root.favsIconSize - cellHeight: iconSize + Kirigami.Units.largeSpacing - cellWidth: cellHeight + Kirigami.Units.largeSpacing - clip: true - z:2 - verticalScrollBarPolicy: PlasmaComponents.ScrollBar.AlwaysOff - height: cellHeight - - anchors.bottom: parent.bottom - anchors.bottomMargin: Kirigami.Units.largeSpacing - anchors.horizontalCenter: parent.horizontalCenter - showLabels: false - dropEnabled: true - dragEnabled: true - - onKeyNavUp: { - if(root.searching){ - globalFavoritesGrid.focus = false - //runnerGrid.tryActivate(0,0) - //runnerGrid.forceActiveFocus() - mainView.currentItem.tryActivate(0,0) - mainView.currentItem.forceActiveFocus() - } - else{ - globalFavoritesGrid.focus = false - allAppsGrid.tryActivate(0,0) - allAppsGrid.forceActiveFocus() - } - } - Keys.onPressed: event => { - if (event.key === Qt.Key_Tab) { - event.accepted = true; - globalFavoritesGrid.focus = false - systemFavoritesGrid.tryActivate(0,0) - systemFavoritesGrid.forceActiveFocus() - } - } - } - - - ItemGridView { - id: systemFavoritesGrid - anchors.top: parent.top - anchors.right: parent.right - clip: true - width: cellWidth - height: systemFavoritesGrid.model ? systemFavoritesGrid.model.count * cellHeight : 0 - cellWidth: iconSize + Kirigami.Units.largeSpacing * 2 - cellHeight: cellWidth - iconSize: root.systemIconSize - z:5 - showLabels: false - model: systemFavorites - dragEnabled: false - dropEnabled: false - Keys.onPressed: event => { - if (event.key === Qt.Key_Tab) { - event.accepted = true; - systemFavoritesGrid.focus = false - searchField.focus = true - } - } - } - - onPressed: mouse => { - if (mouse.button === Qt.RightButton) { - contextMenu.open(mouse.x, mouse.y); - } - } - - onClicked: mouse => { - if (mouse.button === Qt.LeftButton) { - root.toggle(); - } - } - Keys.onPressed: (event)=> { - if(event.modifiers & Qt.ControlModifier ||event.modifiers & Qt.ShiftModifier){ - searchField.focus = true; - return - } - if (event.key === Qt.Key_Escape) { - event.accepted = true; - if (root.searching) { - reset(); - } else { - root.visible = false; - } - return; - } - if (searchField.focus) { - return; - } - if (event.key === Qt.Key_Backspace) { - event.accepted = true; - searchField.backspace(); - } else if (event.text !== "") { - event.accepted = true; - searchField.appendText(event.text); - } - //searchField.focus = true - } - } - - Component.onCompleted: { - rootModel.refresh(); - searchField.forceActiveFocus() - } -} diff --git a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemGridDelegate.qml b/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemGridDelegate.qml deleted file mode 100644 index a985c9a..0000000 --- a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemGridDelegate.qml +++ /dev/null @@ -1,120 +0,0 @@ -/* - SPDX-FileCopyrightText: 2015 Eike Hein - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -import QtQuick 2.15 - -import org.kde.plasma.components 3.0 as PlasmaComponents3 -import org.kde.plasma.core as PlasmaCore -import org.kde.kirigami 2.20 as Kirigami - -import "code/tools.js" as Tools - -Item { - id: item - - width: GridView.view.cellWidth - height: GridView.view.cellHeight - - enabled: !model.disabled - - property bool showLabel: true - - property int itemIndex: model.index - property string favoriteId: model.favoriteId !== undefined ? model.favoriteId : "" - property url url: model.url !== undefined ? model.url : "" - property variant icon: model.decoration !== undefined ? model.decoration : "" - property var m: model - property bool hasActionList: ((model.favoriteId !== null) - || (("hasActionList" in model) && (model.hasActionList === true))) - - Accessible.role: Accessible.MenuItem - Accessible.name: model.display - - function openActionMenu(x, y) { - var actionList = hasActionList ? model.actionList : []; - Tools.fillActionMenu(i18n, actionMenu, actionList, GridView.view.model.favoritesModel, model.favoriteId); - actionMenu.visualParent = item; - actionMenu.open(x, y); - } - - function actionTriggered(actionId, actionArgument) { - var close = (Tools.triggerAction(GridView.view.model, model.index, actionId, actionArgument) === true); - - if (close) { - root.toggle(); - } - } - - Kirigami.Icon { - id: icon - - y: item.showLabel ? (2 * highlightItemSvg.margins.top) : null - - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: item.showLabel ? undefined : parent.verticalCenter - - width: iconSize - height: width - - animated: false - - source: model.decoration - } - - PlasmaComponents3.Label { - id: label - - visible: item.showLabel - - anchors { - top: icon.bottom - topMargin: Kirigami.Units.smallSpacing - left: parent.left - leftMargin: highlightItemSvg.margins.left - right: parent.right - rightMargin: highlightItemSvg.margins.right - } - - horizontalAlignment: Text.AlignHCenter - - maximumLineCount: 2 - elide: Text.ElideMiddle - wrapMode: Text.Wrap - font.pointSize: Kirigami.Theme.defaultFont.pointSize + 0.5 - - text: ("name" in model ? model.name : model.display) - textFormat: Text.PlainText - } - - PlasmaCore.ToolTipArea { - id: toolTip - - property string text: model.display - - anchors.fill: parent - - //active: root.visible && - active: root.visible && ( !item.showLabel || label.truncated) - mainItem: toolTipDelegate - onContainsMouseChanged: item.GridView.view.itemContainsMouseChanged(containsMouse) - } - - Keys.onPressed: event => { - if (event.key === Qt.Key_Menu && hasActionList) { - event.accepted = true; - openActionMenu(item); - } else if ((event.key === Qt.Key_Enter || event.key === Qt.Key_Return)) { - event.accepted = true; - - if ("trigger" in GridView.view.model) { - GridView.view.model.trigger(index, "", null); - root.toggle(); - } - - itemGrid.itemActivated(index, "", null); - } - } -} diff --git a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemGridView.qml b/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemGridView.qml deleted file mode 100644 index 04f923b..0000000 --- a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemGridView.qml +++ /dev/null @@ -1,472 +0,0 @@ -/* - SPDX-FileCopyrightText: 2015 Eike Hein - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -import QtQuick 2.15 -import QtQuick.Controls - -import org.kde.kquickcontrolsaddons 2.0 -import org.kde.ksvg 1.0 as KSvg -import org.kde.plasma.components as PlasmaComponents -import org.kde.plasma.extras 2.0 as PlasmaExtras -import org.kde.kirigami 2.20 as Kirigami - -FocusScope { - id: itemGrid - - signal keyNavLeft - signal keyNavRight - signal keyNavUp - signal keyNavDown - - signal itemActivated(int index, string actionId, string argument) - - property bool dragEnabled: true - property bool dropEnabled: false - property bool showLabels: true - property bool grabFocus: false - property alias currentIndex: gridView.currentIndex - property alias currentItem: gridView.currentItem - property alias contentItem: gridView.contentItem - property alias count: gridView.count - property alias model: gridView.model - property alias verticalLayoutDirection : gridView.verticalLayoutDirection - - property alias cellWidth: gridView.cellWidth - property alias cellHeight: gridView.cellHeight - property alias iconSize: gridView.iconSize - - property var horizontalScrollBarPolicy: PlasmaComponents.ScrollBar.AlwaysOff - property var verticalScrollBarPolicy: PlasmaComponents.ScrollBar.AsNeeded - - onDropEnabledChanged: { - if (!dropEnabled && "dropPlaceHolderIndex" in model) { - model.dropPlaceHolderIndex = -1; - } - } - - onFocusChanged: { - // if (!focus && !root.keyEventProxy.activeFocus) { - if (!focus) { - currentIndex = -1; - } - } - - function currentRow() { - if (currentIndex === -1) { - return -1; - } - - return Math.floor(currentIndex / Math.floor(width / itemGrid.cellWidth)); - } - - function currentCol() { - if (currentIndex === -1) { - return -1; - } - - return currentIndex - (currentRow() * Math.floor(width / itemGrid.cellWidth)); - } - - function lastRow() { - var columns = Math.floor(width / itemGrid.cellWidth); - return Math.ceil(count / columns) - 1; - } - - function tryActivate(row, col) { - if (count) { - var columns = Math.floor(width / itemGrid.cellWidth); - var rows = Math.ceil(count / columns); - row = Math.min(row, rows - 1); - col = Math.min(col, columns - 1); - currentIndex = Math.min(row ? ((Math.max(1, row) * columns) + col) - : col, - count - 1); - - focus = true; - } - } - - function forceLayout() { - gridView.forceLayout(); - } - - ActionMenu { - id: actionMenu - - onActionClicked: { - visualParent.actionTriggered(actionId, actionArgument); - } - } - - DropArea { - id: dropArea - - width: itemGrid.width - height: itemGrid.height - - onPositionChanged: event => { - if (!itemGrid.dropEnabled || gridView.animating || !kicker.dragSource) { - return; - } - - var x = Math.max(0, event.x - (width % itemGrid.cellWidth)); - var cPos = mapToItem(gridView.contentItem, x, event.y); - var item = gridView.itemAt(cPos.x, cPos.y); - - if (item) { - if (kicker.dragSource.parent === gridView.contentItem) { - if (item !== kicker.dragSource) { - item.GridView.view.model.moveRow(dragSource.itemIndex, item.itemIndex); - } - } else if (kicker.dragSource.GridView.view.model.favoritesModel === itemGrid.model - && !itemGrid.model.isFavorite(kicker.dragSource.favoriteId)) { - var hasPlaceholder = (itemGrid.model.dropPlaceholderIndex !== -1); - - itemGrid.model.dropPlaceholderIndex = item.itemIndex; - - if (!hasPlaceholder) { - gridView.currentIndex = (item.itemIndex - 1); - } - } - } else if (kicker.dragSource.parent !== gridView.contentItem - && kicker.dragSource.GridView.view.model.favoritesModel === itemGrid.model - && !itemGrid.model.isFavorite(kicker.dragSource.favoriteId)) { - var hasPlaceholder = (itemGrid.model.dropPlaceholderIndex !== -1); - - itemGrid.model.dropPlaceholderIndex = hasPlaceholder ? itemGrid.model.count - 1 : itemGrid.model.count; - - if (!hasPlaceholder) { - gridView.currentIndex = (itemGrid.model.count - 1); - } - } else { - itemGrid.model.dropPlaceholderIndex = -1; - gridView.currentIndex = -1; - } - } - - onExited: { - if ("dropPlaceholderIndex" in itemGrid.model) { - itemGrid.model.dropPlaceholderIndex = -1; - gridView.currentIndex = -1; - } - } - - onDropped: { - if (kicker.dragSource && kicker.dragSource.parent !== gridView.contentItem && kicker.dragSource.GridView.view.model.favoritesModel === itemGrid.model) { - itemGrid.model.addFavorite(kicker.dragSource.favoriteId, itemGrid.model.dropPlaceholderIndex); - gridView.currentIndex = -1; - } - } - - Timer { - id: resetAnimationDurationTimer - - interval: 120 - repeat: false - - onTriggered: { - gridView.animationDuration = interval - 20; - } - } - - GridView { - id: gridView - - width: itemGrid.width - height: itemGrid.height - - signal itemContainsMouseChanged(bool containsMouse) - - property int iconSize: Kirigami.Units.iconSizes.huge - - property bool animating: false - property int animationDuration: itemGrid.dropEnabled ? resetAnimationDurationTimer.interval : 0 - - focus: true - - currentIndex: -1 - - ScrollBar.vertical: ScrollBar { - snapMode: ScrollBar.SnapAlways - } - - snapMode: GridView.SnapOneRow - move: Transition { - enabled: itemGrid.dropEnabled - - SequentialAnimation { - PropertyAction { target: gridView; property: "animating"; value: true } - - NumberAnimation { - duration: gridView.animationDuration - properties: "x, y" - easing.type: Easing.OutQuad - } - - PropertyAction { target: gridView; property: "animating"; value: false } - } - } - - moveDisplaced: Transition { - enabled: itemGrid.dropEnabled - - SequentialAnimation { - PropertyAction { target: gridView; property: "animating"; value: true } - - NumberAnimation { - duration: gridView.animationDuration - properties: "x, y" - easing.type: Easing.OutQuad - } - - PropertyAction { target: gridView; property: "animating"; value: false } - } - } - - keyNavigationWraps: false - boundsBehavior: Flickable.StopAtBounds - - delegate: ItemGridDelegate { - showLabel: itemGrid.showLabels - } - - highlight: Rectangle { color: colorWithAlpha(Kirigami.Theme.highlightColor,0.65); radius: 10 } - - /* - highlight: Item { - property bool isDropPlaceHolder: "dropPlaceholderIndex" in itemGrid.model && itemGrid.currentIndex === itemGrid.model.dropPlaceholderIndex - - PlasmaExtras.Highlight { - visible: gridView.currentItem && !isDropPlaceHolder - hovered: true - pressed: hoverArea.pressed - - anchors.fill: parent - } - - KSvg.FrameSvgItem { - visible: gridView.currentItem && isDropPlaceHolder - - anchors.fill: parent - - imagePath: "widgets/viewitem" - prefix: "selected" - - opacity: 0.5 - - Kirigami.Icon { - anchors { - right: parent.right - rightMargin: parent.margins.right - bottom: parent.bottom - bottomMargin: parent.margins.bottom - } - - width: Kirigami.Units.iconSizes.smallMedium - height: width - - source: "list-add" - active: false - } - } - } - */ - highlightFollowsCurrentItem: true - highlightMoveDuration: 0 - - onCurrentIndexChanged: { - if (currentIndex !== -1) { - hoverArea.hoverEnabled = false - focus = true; - } - } - - onCountChanged: { - animationDuration = 0; - resetAnimationDurationTimer.start(); - if (count > 0 && itemGrid.grabFocus) { - currentIndex = 0; - focus = true; - forceActiveFocus() - } - - } - - onModelChanged: { - currentIndex = -1; - } - - Keys.onLeftPressed: event => { - if (itemGrid.currentCol() !== 0) { - event.accepted = true; - moveCurrentIndexLeft(); - } else { - itemGrid.keyNavLeft(); - } - } - - Keys.onRightPressed: event => { - var columns = Math.floor(width / cellWidth); - - if (itemGrid.currentCol() !== columns - 1 && currentIndex !== count -1) { - event.accepted = true; - moveCurrentIndexRight(); - } else { - itemGrid.keyNavRight(); - } - } - - Keys.onUpPressed: event => { - if (itemGrid.currentRow() !== 0) { - event.accepted = true; - moveCurrentIndexUp(); - positionViewAtIndex(currentIndex, GridView.Contain); - } else { - itemGrid.keyNavUp(); - } - } - - Keys.onDownPressed: event => { - if (itemGrid.currentRow() < itemGrid.lastRow()) { - // Fix moveCurrentIndexDown()'s lack of proper spatial nav down - // into partial columns. - event.accepted = true; - var columns = Math.floor(itemGrid.width / cellWidth); - var newIndex = currentIndex + columns; - currentIndex = Math.min(newIndex, gridView.count - 1); - positionViewAtIndex(currentIndex, GridView.Visible); - } else { - itemGrid.keyNavDown(); - } - } - - onItemContainsMouseChanged: containsMouse => { - if (!containsMouse) { - //if (!actionMenu.opened) { - // gridView.currentIndex = -1; - //} - hoverArea.pressX = -1; - hoverArea.pressY = -1; - hoverArea.lastX = -1; - hoverArea.lastY = -1; - hoverArea.pressedItem = null; - hoverArea.hoverEnabled = true; - } - } - } - //<>} - - MouseArea { - id: hoverArea - - width: itemGrid.width - Kirigami.Units.gridUnit - height: itemGrid.height - //anchors.fill: parent - - property int pressX: -1 - property int pressY: -1 - property int lastX: -1 - property int lastY: -1 - property Item pressedItem: null - - acceptedButtons: Qt.LeftButton | Qt.RightButton - - hoverEnabled: true - - function updatePositionProperties(x, y) { - // Prevent hover event synthesis in QQuickWindow interfering - // with keyboard navigation by ignoring repeated events with - // identical coordinates. As the work done here would be re- - // dundant in any case, these are safe to ignore. - if (lastX === x && lastY === y) { - return; - } - - lastX = x; - lastY = y; - - var cPos = mapToItem(gridView.contentItem, x, y); - var item = gridView.itemAt(cPos.x, cPos.y); - - if (!item) { - gridView.currentIndex = -1; - pressedItem = null; - } else { - itemGrid.focus = (item.itemIndex !== -1) - itemGrid.forceActiveFocus() //<> - gridView.currentIndex = item.itemIndex; - } - - return item; - } - - onPressed: mouse => { - mouse.accepted = true; - - updatePositionProperties(mouse.x, mouse.y); - - pressX = mouse.x; - pressY = mouse.y; - - if (mouse.button === Qt.RightButton) { - if (gridView.currentItem) { - if (gridView.currentItem.hasActionList) { - var mapped = mapToItem(gridView.currentItem, mouse.x, mouse.y); - gridView.currentItem.openActionMenu(mapped.x, mapped.y); - } - } else { - var mapped = mapToItem(rootItem, mouse.x, mouse.y); - contextMenu.open(mapped.x, mapped.y); - } - } else { - pressedItem = gridView.currentItem; - } - } - - onReleased: mouse => { - mouse.accepted = true; - updatePositionProperties(mouse.x, mouse.y); - - if (!dragHelper.dragging) { - if (pressedItem) { - if ("trigger" in gridView.model) { - gridView.model.trigger(pressedItem.itemIndex, "", null); - root.toggle(); - } - - itemGrid.itemActivated(pressedItem.itemIndex, "", null); - } else if (mouse.button === Qt.LeftButton) { - root.toggle(); - } - } - - pressX = pressY = -1; - pressedItem = null; - } - - onPositionChanged: mouse => { - var item = pressedItem? pressedItem : updatePositionProperties(mouse.x, mouse.y); - - if (gridView.currentIndex !== -1) { - if (itemGrid.dragEnabled && pressX !== -1 && dragHelper.isDrag(pressX, pressY, mouse.x, mouse.y)) { - if ("pluginName" in item.m) { - dragHelper.startDrag(kicker, item.url, item.icon, - "text/x-plasmoidservicename", item.m.pluginName); - } else { - //dragHelper.startDrag(kicker, item.url, item.icon); - dragHelper.startDrag(kicker, item.url); - } - - kicker.dragSource = item; - - pressX = -1; - pressY = -1; - } - } - } - } - } -} diff --git a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemListDelegate.qml b/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemListDelegate.qml deleted file mode 100644 index 4e071b2..0000000 --- a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemListDelegate.qml +++ /dev/null @@ -1,137 +0,0 @@ -/* - SPDX-FileCopyrightText: 2015 Eike Hein - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -import QtQuick 2.15 - -import org.kde.plasma.components 3.0 as PlasmaComponents3 -import org.kde.plasma.core as PlasmaCore -import org.kde.kirigami 2.20 as Kirigami - -import "code/tools.js" as Tools - -Item { - id: item - - width: ListView.view.width - height: 40 - - enabled: !model.disabled - - property bool showLabel: true - - property int itemIndex: model.index - property string favoriteId: model.favoriteId !== undefined ? model.favoriteId : "" - property url url: model.url !== undefined ? model.url : "" - property variant icon: model.decoration !== undefined ? model.decoration : "" - property var m: model - property bool hasActionList: ((model.favoriteId !== null) - || (("hasActionList" in model) && (model.hasActionList === true))) - - Accessible.role: Accessible.MenuItem - Accessible.name: model.display - - function openActionMenu(x, y) { - var actionList = hasActionList ? model.actionList : []; - Tools.fillActionMenu(i18n, actionMenu, actionList, GridView.view.model.favoritesModel, model.favoriteId); - actionMenu.visualParent = item; - actionMenu.open(x, y); - } - - function actionTriggered(actionId, actionArgument) { - var close = (Tools.triggerAction(GridView.view.model, model.index, actionId, actionArgument) === true); - - if (close) { - root.toggle(); - } - } - - Kirigami.Icon { - id: icon - - //y: item.showLabel ? (2 * highlightItemSvg.margins.top) : undefined - - anchors.left: parent.left - anchors.leftMargin: Kirigami.Units.largeSpacing - anchors.verticalCenter: parent.verticalCenter - - width: iconSize - height: width - - animated: false - - source: model.decoration - } - - PlasmaComponents3.Label { - id: label - visible: item.showLabel - anchors { - left: icon.right - leftMargin: Kirigami.Units.largeSpacing - right: desc.left - rightMargin: Kirigami.Units.largeSpacing - verticalCenter: icon.verticalCenter - - } - horizontalAlignment: Text.AlignLeft - maximumLineCount: 1 - elide: Text.ElideMiddle - //wrapMode: Text.Wrap - color: Kirigami.Theme.textColor - font.pointSize: Kirigami.Theme.defaultFont.pointSize - text: ("name" in model ? model.name : model.display) - textFormat: Text.PlainText - } - - PlasmaComponents3.Label { - id: desc - anchors { - //top: itemColumns == 2 ? label.bottom: undefined - //left: itemColumns == 2 ? icon.right : undefined - leftMargin: Kirigami.Units.largeSpacing - right: parent.right - rightMargin: Kirigami.Units.largeSpacing - verticalCenter: icon.verticalCenter - } - horizontalAlignment: Text.AlignRight - maximumLineCount: 1 - elide: Text.ElideMiddle - //wrapMode: Text.Wrap - - color: colorWithAlpha(Kirigami.Theme.textColor,0.4) - font.pointSize: Kirigami.Theme.defaultFont.pointSize - 1 - text: ("description" in model ? model.description : "") - textFormat: Text.PlainText - } - - PlasmaCore.ToolTipArea { - id: toolTip - - property string text: model.display - - anchors.fill: parent - active: root.visible && label.truncated - mainItem: toolTipDelegate - - //<>onContainsMouseChanged: item.GridView.view.itemContainsMouseChanged(containsMouse) - } - - Keys.onPressed: event => { - if (event.key === Qt.Key_Menu && hasActionList) { - event.accepted = true; - openActionMenu(item); - } else if ((event.key === Qt.Key_Enter || event.key === Qt.Key_Return)) { - event.accepted = true; - - if ("trigger" in GridView.view.model) { - GridView.view.model.trigger(index, "", null); - root.toggle(); - } - - itemGrid.itemActivated(index, "", null); - } - } -} diff --git a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemListDialog.qml b/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemListDialog.qml deleted file mode 100644 index a6d78f0..0000000 --- a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemListDialog.qml +++ /dev/null @@ -1,99 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013-2014 Eike Hein - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -import QtQuick 2.15 - -import org.kde.plasma.core as PlasmaCore -import org.kde.plasma.plasmoid 2.0 -import org.kde.kirigami 2.20 as Kirigami - -import org.kde.plasma.private.kicker 0.1 as Kicker - -Kicker.SubMenu { - id: itemDialog - - property alias focusParent: itemListView.focusParent - property alias model: funnelModel.sourceModel - - property bool aboutToBeDestroyed: false - - visible: false - hideOnWindowDeactivate: kicker.hideOnWindowDeactivate - location: PlasmaCore.Types.Floating - offset: Kirigami.Units.smallSpacing - - onWindowDeactivated: { - if (!aboutToBeDestroyed) { - kicker.expanded = false; - } - } - - mainItem: ItemListView { - id: itemListView - - height: { - const m = funnelModel.sourceModel; - - if (m === null || m === undefined) { - // TODO: setting height to 0 triggers a warning in PlasmaQuick::Dialog - return 0; - } - - return Math.min( - // either fit in screen boundaries (cut to the nearest item/separator boundary), ... - __subFloorMultipleOf( - itemDialog.availableScreenRectForItem(itemListView).height - - itemDialog.margins.top - - itemDialog.margins.bottom, - itemHeight - ) + m.separatorCount * (separatorHeight - itemHeight) - , - // ...or fit the content itself -- whichever is shorter. - ((m.count - m.separatorCount) * itemHeight) - + (m.separatorCount * separatorHeight) - ); - } - - // get x rounded down to the multiple of y, minus extra y. - function __subFloorMultipleOf(x : real, y : real) : real { - return (Math.floor(x / y) - 1) * y; - } - - iconsEnabled: true - - dialog: itemDialog - - model: funnelModel - - Kicker.FunnelModel { - id: funnelModel - - property bool sorted: sourceModel?.sorted ?? false - - Component.onCompleted: { - kicker.reset.connect(funnelModel.reset); - } - - onCountChanged: { - if (sourceModel && count === 0) { - itemDialog.delayedDestroy(); - } - } - - onSourceModelChanged: { - itemListView.currentIndex = -1; - } - } - } - - function delayedDestroy() { - aboutToBeDestroyed = true; - Plasmoid.hideOnWindowDeactivate = false; - visible = false; - - Qt.callLater(() => itemDialog.destroy()); - } -} diff --git a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemListView.qml b/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemListView.qml deleted file mode 100644 index fccb84f..0000000 --- a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemListView.qml +++ /dev/null @@ -1,267 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013-2014 Eike Hein - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -import QtQuick 2.15 -import QtQuick.Controls - -import org.kde.kquickcontrolsaddons 2.0 -import org.kde.plasma.extras 2.0 as PlasmaExtras -import org.kde.kirigami 2.20 as Kirigami - -FocusScope { - id: itemList - - property real minimumWidth: Kirigami.Units.gridUnit * 14 - property real maximumWidth: minimumWidth * 2 - - width: minimumWidth - height: listView.contentHeight - - signal exited - signal keyNavigationAtListEnd - signal appendSearchText(string text) - - property Item focusParent: null - property QtObject dialog: null - property QtObject childDialog: null - property bool iconsEnabled: false - property int itemHeight: Math.ceil((Math.max(Kirigami.Units.iconSizes.sizeForLabels, Kirigami.Units.iconSizes.small) - + Math.max(highlightItemSvg.margins.top + highlightItemSvg.margins.bottom, - listItemSvg.margins.top + listItemSvg.margins.bottom)) / 2) * 2 - property int separatorHeight: model.sorted === true ? 0 : lineSvg.horLineHeight + (2 * Kirigami.Units.smallSpacing) - - property alias currentIndex: listView.currentIndex - property alias currentItem: listView.currentItem - property alias keyNavigationWraps: listView.keyNavigationWraps - property alias showChildDialogs: listView.showChildDialogs - property alias model: listView.model - property alias count: listView.count - property alias containsMouse: listener.containsMouse - property alias resetOnExitDelay: resetIndexTimer.interval - - onFocusParentChanged: { - appendSearchText.connect(focusParent.appendSearchText); - } - - Timer { - id: dialogSpawnTimer - - property bool focusOnSpawn: false - - interval: 70 - repeat: false - - onTriggered: { - if (!kicker.expanded || model === undefined || currentIndex == -1) { - return; - } - - if (itemList.childDialog != null) { - itemList.childDialog.delayedDestroy(); - } - - // Gets reenabled after the dialog spawn causes a focus-in on the dialog window. - kicker.hideOnWindowDeactivate = false; - - itemList.childDialog = itemListDialogComponent.createObject(itemList); - itemList.childDialog.focusParent = itemList; - itemList.childDialog.visualParent = listView.currentItem; - itemList.childDialog.model = model.modelForRow(listView.currentIndex); - itemList.childDialog.visible = true; - - windowSystem.forceActive(itemList.childDialog.mainItem); - itemList.childDialog.mainItem.focus = true; - - if (focusOnSpawn) { - itemList.childDialog.mainItem.showChildDialogs = false; - itemList.childDialog.mainItem.currentIndex = 0; - itemList.childDialog.mainItem.showChildDialogs = true; - } - } - } - - Timer { - id: resetIndexTimer - - interval: (dialog != null) ? 50 : 150 - repeat: false - - onTriggered: { - if (focus && (!itemList.childDialog || !itemList.childDialog.mainItem.containsMouse)) { - currentIndex = -1; - itemList.exited(); - } - } - } - - MouseEventListener { - id: listener - - anchors.fill: parent - - hoverEnabled: true - - onContainsMouseChanged: { - listView.eligibleWidth = listView.width; - - if (containsMouse) { - resetIndexTimer.stop(); - itemList.forceActiveFocus(); - } else if ((!itemList.childDialog || !dialog) - && (!currentItem || !currentItem.menu.opened)) { - resetIndexTimer.start(); - } - } - - ScrollView { - anchors.fill: parent - - focus: true - - ListView { - id: listView - - property bool showChildDialogs: true - property int eligibleWidth: width - - currentIndex: -1 - - boundsBehavior: Flickable.StopAtBounds - snapMode: ListView.SnapToItem - spacing: 0 - keyNavigationEnabled: false - - delegate: ItemListDelegate { - onFullTextWidthChanged: { - if (fullTextWidth > itemList.width) itemList.width = Math.min(fullTextWidth, itemList.maximumWidth); - } - } - - highlight: PlasmaExtras.Highlight { - visible: !listView.currentItem || !listView.currentItem.isSeparator - pressed: listView.currentItem && listView.currentItem.pressed && !listView.currentItem.hasChildren - active: listView.currentItem && listView.currentItem.hovered - } - - highlightMoveDuration: 0 - - onCountChanged: { - if (currentIndex == 0) { - currentItem.forceActiveFocus(); - } else { - currentIndex = -1; - } - } - - onCurrentIndexChanged: { - if (currentIndex != -1) { - if (itemList.childDialog) { - if (currentItem && currentItem.hasChildren) { - itemList.childDialog.mainItem.width = itemList.minimumWidth; - itemList.childDialog.model = model.modelForRow(currentIndex); - itemList.childDialog.visualParent = listView.currentItem; - } else { - itemList.childDialog.delayedDestroy(); - } - - return; - } - - if (currentItem == null || !currentItem.hasChildren || !kicker.expanded) { - dialogSpawnTimer.stop(); - - return; - } - - if (showChildDialogs) { - dialogSpawnTimer.focusOnSpawn = false; - dialogSpawnTimer.restart(); - } - } else if (itemList.childDialog != null) { - itemList.childDialog.delayedDestroy(); - itemList.childDialog = null; - } - } - - onCurrentItemChanged: { - if (currentItem) { - currentItem.menu.closed.connect(resetIndexTimer.restart); - } - } - } - - Keys.onPressed: event => { - if (event.key === Qt.Key_Right || event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { - if (itemList.childDialog === null && currentItem != null && currentItem.hasChildren) { - dialogSpawnTimer.focusOnSpawn = true; - dialogSpawnTimer.restart(); - } else if (currentItem != null && currentItem.hasChildren) { - windowSystem.forceActive(itemList.childDialog.mainItem); - itemList.childDialog.mainItem.focus = true; - itemList.childDialog.mainItem.currentIndex = 0; - } - } else if (event.key === Qt.Key_Up) { - event.accepted = true; - - if (!keyNavigationWraps && currentIndex == 0) { - itemList.keyNavigationAtListEnd(); - - return; - } - - showChildDialogs = false; - listView.decrementCurrentIndex(); - - if (currentItem.isSeparator) { - listView.decrementCurrentIndex(); - } - listView.currentItem.forceActiveFocus() - - showChildDialogs = true; - } else if (event.key === Qt.Key_Down) { - event.accepted = true; - - if (!keyNavigationWraps && currentIndex == count - 1) { - itemList.keyNavigationAtListEnd(); - - return; - } - - showChildDialogs = false; - listView.incrementCurrentIndex(); - - if (currentItem.isSeparator) { - listView.incrementCurrentIndex(); - } - listView.currentItem.forceActiveFocus() - - showChildDialogs = true; - } else if (event.key === Qt.Key_Left && dialog != null) { - dialog.destroy(); - } else if (event.key === Qt.Key_Escape) { - kicker.expanded = false; - } else if (event.key === Qt.Key_Tab) { - //do nothing, and skip appending text - } else if (event.text !== "") { - if (/[\x00-\x1F\x7F]/.test(event.text)) { - // We still want to focus it - appendSearchText(""); - } else { - appendSearchText(event.text); - } - } - } - } - } - - Component.onCompleted: { - windowSystem.monitorWindowFocus(itemList); - - if (dialog == null) { - appendSearchText.connect(root.appendSearchText); - } - } -} diff --git a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemMultiGridView.qml b/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemMultiGridView.qml deleted file mode 100644 index 8427701..0000000 --- a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/ItemMultiGridView.qml +++ /dev/null @@ -1,235 +0,0 @@ -/* - SPDX-FileCopyrightText: 2015 Eike Hein - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -import QtQuick - -import org.kde.ksvg 1.0 as KSvg -import org.kde.plasma.components as PlasmaComponents -import org.kde.plasma.extras 2.0 as PlasmaExtras -import org.kde.kirigami 2.20 as Kirigami -import org.kde.plasma.private.kicker 0.1 as Kicker - -PlasmaComponents.ScrollView { - id: itemMultiGrid - - anchors { - top: parent.top - } - - width: parent.width - - implicitHeight: itemColumn.implicitHeight - - signal keyNavLeft(int subGridIndex) - signal keyNavRight(int subGridIndex) - signal keyNavUp() - signal keyNavDown() - - property bool grabFocus: false - - property alias model: repeater.model - property alias count: repeater.count - property alias flickableItem: flickable - - function subGridAt(index) { - return repeater.itemAt(index).itemGrid; - } - - function tryActivate(row, col) { // FIXME TODO: Cleanup messy algo. - if (flickable.contentY > 0) { - row = 0; - } - - var target = null; - var rows = 0; - - for (var i = 0; i < repeater.count; i++) { - var grid = subGridAt(i); - - if (rows <= row) { - target = grid; - rows += grid.lastRow() + 2; // Header counts as one. - } else { - break; - } - } - - if (target) { - rows -= (target.lastRow() + 2); - target.tryActivate(row - rows, col); - } - } - - onFocusChanged: { - if (!focus) { - for (var i = 0; i < repeater.count; i++) { - subGridAt(i).focus = false; - } - } - } - - Flickable { - id: flickable - - flickableDirection: Flickable.VerticalFlick - contentHeight: itemColumn.implicitHeight - //focusPolicy: Qt.NoFocus - - Column { - id: itemColumn - - width: itemMultiGrid.width - Kirigami.Units.gridUnit - - Repeater { - id: repeater - - delegate: Item { - width: itemColumn.width - Kirigami.Units.gridUnit - height: headerHeight + gridView.height + (index == repeater.count - 1 ? 0 : footerHeight) - - property int headerHeight: (gridViewLabel.height - + gridViewLabelUnderline.height + Kirigami.Units.gridUnit) - property int footerHeight: (Math.ceil(headerHeight / cellSize) * cellSize) - headerHeight - - property Item itemGrid: gridView - - Kirigami.Heading { - id: gridViewLabel - - anchors.top: parent.top - - x: Kirigami.Units.smallSpacing - width: parent.width - x - height: dummyHeading.height - - elide: Text.ElideRight - wrapMode: Text.NoWrap - opacity: 1.0 - - color: "white" // FIXME TODO: Respect theming? - - level: 1 - - text: repeater.model.modelForRow(index).description - textFormat: Text.PlainText - } - - KSvg.SvgItem { - id: gridViewLabelUnderline - - anchors.top: gridViewLabel.bottom - - width: parent.width - Kirigami.Units.gridUnit - height: lineSvg.horLineHeight - - svg: lineSvg - elementId: "horizontal-line" - } - - MouseArea { - width: parent.width - height: parent.height - - onClicked: root.toggle() - } - - ItemGridView { - id: gridView - - anchors { - top: gridViewLabelUnderline.bottom - topMargin: Kirigami.Units.gridUnit - } - - width: parent.width - height: Math.ceil(count / Math.floor(width / cellSize)) * cellSize - - cellWidth: cellSize - cellHeight: cellSize - iconSize: root.iconSize - - verticalScrollBarPolicy: PlasmaComponents.ScrollBar.AlwaysOff - - model: repeater.model.modelForRow(index) - - onFocusChanged: { - if (focus) { - itemMultiGrid.focus = true; - } - } - - onCountChanged: { - if (itemMultiGrid.grabFocus && index == 0 && count > 0) { - currentIndex = 0; - focus = true; - } - } - - onCurrentItemChanged: { - if (!currentItem) { - return; - } - - if (index == 0 && currentRow() === 0) { - flickable.contentY = 0; - return; - } - - var y = currentItem.y; - y = contentItem.mapToItem(flickable.contentItem, 0, y).y; - - if (y < flickable.contentY) { - flickable.contentY = y; - } else { - y += cellSize; - y -= flickable.contentY; - y -= itemMultiGrid.height; - - if (y > 0) { - flickable.contentY += y; - } - } - } - - onKeyNavLeft: { - itemMultiGrid.keyNavLeft(index); - } - - onKeyNavRight: { - itemMultiGrid.keyNavRight(index); - } - - onKeyNavUp: { - if (index > 0) { - var prevGrid = subGridAt(index - 1); - prevGrid.tryActivate(prevGrid.lastRow(), currentCol()); - } else { - itemMultiGrid.keyNavUp(); - } - } - - onKeyNavDown: { - if (index < repeater.count - 1) { - subGridAt(index + 1).tryActivate(0, currentCol()); - } else { - itemMultiGrid.keyNavDown(); - } - } - } - - // HACK: Steal wheel events from the nested grid view and forward them to - // the ScrollView's internal WheelArea. - Kicker.WheelInterceptor { - anchors.fill: gridView - z: 1 - - destination: findWheelArea(itemMultiGrid) - } - } - } - } - } -} diff --git a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/SideBarItem.qml b/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/SideBarItem.qml deleted file mode 100644 index dd6a69b..0000000 --- a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/SideBarItem.qml +++ /dev/null @@ -1,142 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013-2015 Eike Hein - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -import QtQuick 2.15 - -import org.kde.kquickcontrolsaddons 2.0 -import org.kde.plasma.core as PlasmaCore -import org.kde.kirigami 2.20 as Kirigami -import org.kde.plasma.plasmoid 2.0 - -import "code/tools.js" as Tools - -Item { - id: item - - width: root.width - height: root.width - - signal actionTriggered(string actionId, variant actionArgument) - signal aboutToShowActionMenu(variant actionMenu) - - property bool hasActionList: ((model.favoriteId !== null) - || (("hasActionList" in model) && (model.hasActionList !== null))) - property int itemIndex: model.index - - onAboutToShowActionMenu: actionMenu => { - const actionList = (model.hasActionList !== null) ? model.actionList : []; - Tools.fillActionMenu(i18n, actionMenu, actionList, repeater.model, model.favoriteId); - } - - onActionTriggered: (actionId, actionArgument) => { - if (Tools.triggerAction(repeater.model, model.index, actionId, actionArgument) === true) { - kicker.expanded = false; - } - } - - function openActionMenu(visualParent, x, y) { - aboutToShowActionMenu(actionMenu); - actionMenu.visualParent = visualParent; - actionMenu.open(x, y); - } - - ActionMenu { - id: actionMenu - - onActionClicked: { - actionTriggered(actionId, actionArgument); - } - } - - Kirigami.Icon { - anchors.fill: parent - - active: toolTip.containsMouse - - source: model.decoration - } - - MouseEventListener { - id: listener - - anchors { - fill: parent - leftMargin: - sideBar.margins.left - rightMargin: - sideBar.margins.right - } - - enabled: (item.parent && !item.parent.animating) - - property bool pressed: false - property int pressX: -1 - property int pressY: -1 - - hoverEnabled: true - acceptedButtons: Qt.LeftButton | Qt.RightButton - - onPressed: { - if (mouse.buttons & Qt.RightButton) { - if (item.hasActionList) { - item.openActionMenu(item, mouse.x, mouse.y); - } - } else { - pressed = true; - pressX = mouse.x; - pressY = mouse.y; - } - } - - onReleased: { - if (pressed) { - repeater.model.trigger(index, "", null); - kicker.expanded = false; - } - - pressed = false; - pressX = -1; - pressY = -1; - } - - onContainsMouseChanged: { - if (!containsMouse) { - pressed = false; - pressX = -1; - pressY = -1; - } - } - - onPositionChanged: { - if (pressX !== -1 && dragHelper.isDrag(pressX, pressY, mouse.x, mouse.y)) { - kicker.dragSource = item; - dragHelper.startDrag(kicker, model.url, model.icon); - pressed = false; - pressX = -1; - pressY = -1; - - return; - } - } - } - - PlasmaCore.ToolTipArea { - id: toolTip - - property string text: model.display - - anchors { - fill: parent - leftMargin: - sideBar.margins.left - rightMargin: - sideBar.margins.right - } - - interactive: false - location: (((Plasmoid.location === PlasmaCore.Types.RightEdge) - || (Qt.application.layoutDirection === Qt.RightToLeft)) - ? PlasmaCore.Types.RightEdge : PlasmaCore.Types.LeftEdge) - - mainItem: toolTipDelegate - } -} diff --git a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/SideBarSection.qml b/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/SideBarSection.qml deleted file mode 100644 index 81c6163..0000000 --- a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/SideBarSection.qml +++ /dev/null @@ -1,83 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013-2014 Eike Hein - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -import QtQuick 2.15 - -import org.kde.draganddrop 2.0 -import org.kde.kirigami 2.20 as Kirigami - -DropArea { - id: root - - width: Kirigami.Units.iconSizes.medium - height: contentHeight - - anchors.horizontalCenter: parent.horizontalCenter - - property int contentHeight: model ? (model.count * Kirigami.Units.iconSizes.medium) + ((model.count - 1) * flow.spacing) : 0 - - property alias model: repeater.model - - onDragMove: event => { - if (flow.animating) { - return; - } - - var above = flow.childAt(event.x, event.y); - - if (above && above !== kicker.dragSource && dragSource.parent == flow) { - repeater.model.moveRow(dragSource.itemIndex, above.itemIndex); - } - - } - - Flow { - id: flow - - anchors.fill: parent - - property bool animating: false - property int animationDuration: resetAnimationDurationTimer.interval - - move: Transition { - SequentialAnimation { - PropertyAction { target: flow; property: "animating"; value: true } - - NumberAnimation { - duration: flow.animationDuration - properties: "x, y" - easing.type: Easing.OutQuad - } - - PropertyAction { target: flow; property: "animating"; value: false } - } - } - - spacing: (2 * Kirigami.Units.smallSpacing) - - Repeater { - id: repeater - - delegate: SideBarItem {} - - onCountChanged: { - flow.animationDuration = 0; - resetAnimationDurationTimer.start(); - } - } - } - - Timer { - id: resetAnimationDurationTimer - - interval: 150 - repeat: false - - onTriggered: { - flow.animationDuration = interval - 20; - } - } -} diff --git a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/code/tools.js b/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/code/tools.js deleted file mode 100644 index fa1cbd3..0000000 --- a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/code/tools.js +++ /dev/null @@ -1,181 +0,0 @@ -/* - SPDX-FileCopyrightText: 2013 Aurélien Gâteau - SPDX-FileCopyrightText: 2013-2015 Eike Hein - SPDX-FileCopyrightText: 2017 Ivan Cukic - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -.pragma library - -function fillActionMenu(i18n, actionMenu, actionList, favoriteModel, favoriteId) { - // Accessing actionList can be a costly operation, so we don't - // access it until we need the menu. - - var actions = createFavoriteActions(i18n, favoriteModel, favoriteId); - - if (actions) { - if (actionList && actionList.length > 0) { - var actionListCopy = Array.from(actionList); - var separator = { "type": "separator" }; - actionListCopy.push(separator); - // actionList = actions.concat(actionList); // this crashes Qt O.o - actionListCopy.push.apply(actionListCopy, actions); - actionList = actionListCopy; - } else { - actionList = actions; - } - } - - actionMenu.actionList = actionList; -} - -function createFavoriteActions(i18n, favoriteModel, favoriteId) { - if (!favoriteModel || !favoriteModel.enabled || !favoriteId) { - return null; - } - - - if (favoriteModel.activities === undefined || - favoriteModel.activities.runningActivities.length <= 1) { - var action = {}; - - if (favoriteModel.isFavorite(favoriteId)) { - action.text = i18n("Remove from Favorites"); - action.icon = "bookmark-remove"; - action.actionId = "_kicker_favorite_remove"; - } else if (favoriteModel.maxFavorites === -1 || favoriteModel.count < favoriteModel.maxFavorites) { - action.text = i18n("Add to Favorites"); - action.icon = "bookmark-new"; - action.actionId = "_kicker_favorite_add"; - } else { - return null; - } - - action.actionArgument = { favoriteModel: favoriteModel, favoriteId: favoriteId }; - - return [action]; - - } else { - var actions = []; - - var linkedActivities = favoriteModel.linkedActivitiesFor(favoriteId); - - var activities = favoriteModel.activities.runningActivities; - - // Adding the item to link/unlink to all activities - - var linkedToAllActivities = - !(linkedActivities.indexOf(":global") === -1); - - actions.push({ - text : i18n("On All Activities"), - checkable : true, - - actionId : linkedToAllActivities ? - "_kicker_favorite_remove_from_activity" : - "_kicker_favorite_set_to_activity", - checked : linkedToAllActivities, - - actionArgument : { - favoriteModel: favoriteModel, - favoriteId: favoriteId, - favoriteActivity: "" - } - }); - - - // Adding items for each activity separately - - var addActivityItem = function(activityId, activityName) { - var linkedToThisActivity = - !(linkedActivities.indexOf(activityId) === -1); - - actions.push({ - text : activityName, - checkable : true, - checked : linkedToThisActivity && !linkedToAllActivities, - - actionId : - // If we are on all activities, and the user clicks just one - // specific activity, unlink from everything else - linkedToAllActivities ? "_kicker_favorite_set_to_activity" : - - // If we are linked to the current activity, just unlink from - // that single one - linkedToThisActivity ? "_kicker_favorite_remove_from_activity" : - - // Otherwise, link to this activity, but do not unlink from - // other ones - "_kicker_favorite_add_to_activity", - - actionArgument : { - favoriteModel : favoriteModel, - favoriteId : favoriteId, - favoriteActivity : activityId - } - }); - }; - - // Adding the item to link/unlink to the current activity - - addActivityItem(favoriteModel.activities.currentActivity, i18n("On the Current Activity")); - - actions.push({ - type: "separator", - actionId: "_kicker_favorite_separator" - }); - - // Adding the items for each activity - - activities.forEach(function(activityId) { - addActivityItem(activityId, favoriteModel.activityNameForId(activityId)); - }); - - return [{ - text : i18n("Show in Favorites"), - icon : "favorite", - subActions : actions - }]; - } -} - -function triggerAction(model, index, actionId, actionArgument) { - function startsWith(txt, needle) { - return txt.substr(0, needle.length) === needle; - } - - if (startsWith(actionId, "_kicker_favorite_")) { - handleFavoriteAction(actionId, actionArgument); - return; - } - - var closeRequested = model.trigger(index, actionId, actionArgument); - - if (closeRequested) { - return true; - } - - return false; -} - -function handleFavoriteAction(actionId, actionArgument) { - var favoriteId = actionArgument.favoriteId; - var favoriteModel = actionArgument.favoriteModel; - - if (favoriteModel === null || favoriteId === null) { - return null; - } - - if (actionId === "_kicker_favorite_remove") { - favoriteModel.removeFavorite(favoriteId); - } else if (actionId === "_kicker_favorite_add") { - favoriteModel.addFavorite(favoriteId); - } else if (actionId === "_kicker_favorite_remove_from_activity") { - favoriteModel.removeFavoriteFrom(favoriteId, actionArgument.favoriteActivity); - } else if (actionId === "_kicker_favorite_add_to_activity") { - favoriteModel.addFavoriteTo(favoriteId, actionArgument.favoriteActivity); - } else if (actionId === "_kicker_favorite_set_to_activity") { - favoriteModel.setFavoriteOn(favoriteId, actionArgument.favoriteActivity); - } -} diff --git a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/main.qml b/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/main.qml deleted file mode 100644 index f0c30ad..0000000 --- a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/contents/ui/main.qml +++ /dev/null @@ -1,274 +0,0 @@ - /* - SPDX-FileCopyrightText: 2014-2015 Eike Hein - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -import QtQuick 2.15 -import QtQuick.Layouts 1.15 - -import org.kde.plasma.components 3.0 as PlasmaComponents3 -import org.kde.plasma.core as PlasmaCore -import org.kde.ksvg 1.0 as KSvg -import org.kde.plasma.plasmoid 2.0 -import org.kde.kirigami 2.20 as Kirigami - -import org.kde.plasma.private.kicker 0.1 as Kicker -import org.kde.plasma.plasma5support 2.0 as P5Support - - -PlasmoidItem { - id: kicker - - anchors.fill: parent - - signal reset - - property bool isDash: true // Plasmoid.pluginName === "org.kde.plasma.kickerdash" - - switchWidth: isDash || !fullRepresentationItem ? 0 :fullRepresentationItem.Layout.minimumWidth - switchHeight: isDash || !fullRepresentationItem ? 0 :fullRepresentationItem.Layout.minimumHeight - - // this is a bit of a hack to prevent Plasma from spawning a dialog on its own when we're Dash - preferredRepresentation: isDash ?fullRepresentation : null - - compactRepresentation: isDash ? null : compactRepresentation - fullRepresentation: compactRepresentation - - property Component itemListDialogComponent: Qt.createComponent(Qt.resolvedUrl("./ItemListDialog.qml")) - property Item dragSource: null - - property QtObject globalFavorites: rootModel.favoritesModel - property QtObject systemFavorites: rootModel.systemFavoritesModel - - Plasmoid.icon: Plasmoid.configuration.useCustomButtonImage ? Plasmoid.configuration.customButtonImage : Plasmoid.configuration.icon - - onSystemFavoritesChanged: { - systemFavorites.favorites = Plasmoid.configuration.favoriteSystemActions; - } - - function action_menuedit() { - processRunner.runMenuEditor(); - } - - function updateSvgMetrics() { - lineSvg.horLineHeight = lineSvg.elementSize("horizontal-line").height; - lineSvg.vertLineWidth = lineSvg.elementSize("vertical-line").width; - } - - Component { - id: compactRepresentation - CompactRepresentation {} - } - - Kicker.RootModel { - id: rootModel - - autoPopulate: false - - appNameFormat: Plasmoid.configuration.appNameFormat - flat: kicker.isDash || Plasmoid.configuration.limitDepth - sorted: Plasmoid.configuration.alphaSort - showSeparators: !kicker.isDash - // TODO: appletInterface property now can be ported to "applet" and have the real Applet* assigned directly - appletInterface: kicker - - showAllApps: kicker.isDash - showAllAppsCategorized: false //<> true - showTopLevelItems: !kicker.isDash - showRecentApps: true //<>Plasmoid.configuration.showRecentApps - showRecentDocs: true //<>Plasmoid.configuration.showRecentDocs - recentOrdering: Plasmoid.configuration.recentOrdering - - onShowRecentAppsChanged: { - Plasmoid.configuration.showRecentApps = showRecentApps; - } - - onShowRecentDocsChanged: { - Plasmoid.configuration.showRecentDocs = showRecentDocs; - } - - onRecentOrderingChanged: { - Plasmoid.configuration.recentOrdering = recentOrdering; - } - - Component.onCompleted: { - favoritesModel.initForClient("org.kde.plasma.kicker.favorites.instance-" + Plasmoid.id) - - if (!Plasmoid.configuration.favoritesPortedToKAstats) { - if (favoritesModel.count < 1) { - favoritesModel.portOldFavorites(Plasmoid.configuration.favoriteApps); - } - Plasmoid.configuration.favoritesPortedToKAstats = true; - } - } - } - - Connections { - target: globalFavorites - - function onFavoritesChanged() { - Plasmoid.configuration.favoriteApps = target.favorites; - } - } - - Connections { - target: systemFavorites - - function onFavoritesChanged() { - Plasmoid.configuration.favoriteSystemActions = target.favorites; - } - } - - Connections { - target: Plasmoid.configuration - - function onFavoriteAppsChanged() { - globalFavorites.favorites = Plasmoid.configuration.favoriteApps; - } - - function onFavoriteSystemActionsChanged() { - systemFavorites.favorites = Plasmoid.configuration.favoriteSystemActions; - } - } - - P5Support.DataSource { - id: pmEngine - engine: "powermanagement" - connectedSources: ["PowerDevil", "Sleep States"] - function performOperation(what) { - var service = serviceForSource("PowerDevil") - var operation = service.operationDescription(what) - service.startOperationCall(operation) - } - } - - - Kicker.RunnerModel { - id: runnerModel - - appletInterface: kicker - - favoritesModel: globalFavorites - mergeResults: true - - runners: { - const results = ["krunner_services", "krunner_systemsettings"]; - - if (kicker.isDash) { - results.push("krunner_sessions", "krunner_powerdevil", "calculator", "unitconverter"); - } - - if (Plasmoid.configuration.useExtraRunners) { - results.push(...Plasmoid.configuration.extraRunners); - } - - return results; - } - } - - Kicker.DragHelper { - id: dragHelper - - dragIconSize: Kirigami.Units.iconSizes.medium - } - - Kicker.ProcessRunner { - id: processRunner - } - - Kicker.WindowSystem { - id: windowSystem - } - - KSvg.FrameSvgItem { - id: highlightItemSvg - - visible: false - - imagePath: "widgets/viewitem" - prefix: "hover" - } - - KSvg.FrameSvgItem { - id: listItemSvg - - visible: false - - imagePath: "widgets/listitem" - prefix: "normal" - } - - KSvg.Svg { - id: lineSvg - imagePath: "widgets/line" - - property int horLineHeight - property int vertLineWidth - } - - PlasmaComponents3.Label { - id: toolTipDelegate - - width: contentWidth - height: undefined - font.pointSize: Kirigami.Theme.defaultFont.pointSize + 0.5 - - property Item toolTip - - text: toolTip ? toolTip.text : "" - } - - Timer { - id: justOpenedTimer - - repeat: false - interval: 600 - } - - Connections { - target: kicker - - function onExpandedChanged(expanded) { - if (expanded) { - windowSystem.monitorWindowVisibility(Plasmoid.fullRepresentationItem); - justOpenedTimer.start(); - } else { - kicker.reset(); - } - } - } - - function resetDragSource() { - dragSource = null; - } - - function enableHideOnWindowDeactivate() { - kicker.hideOnWindowDeactivate = true; - } - - Plasmoid.contextualActions: [ - PlasmaCore.Action { - text: i18n("Edit Applications…") - icon.name: "kmenuedit" - visible: Plasmoid.immutability !== PlasmaCore.Types.SystemImmutable - onTriggered: processRunner.runMenuEditor() - } - ] - - Component.onCompleted: { - if (Plasmoid.hasOwnProperty("activationTogglesExpanded")) { - Plasmoid.activationTogglesExpanded = !kicker.isDash - } - - windowSystem.focusIn.connect(enableHideOnWindowDeactivate); - kicker.hideOnWindowDeactivate = true; - - updateSvgMetrics(); - PlasmaCore.Theme.themeChanged.connect(updateSvgMetrics); - - rootModel.refreshed.connect(reset); - - dragHelper.dropped.connect(resetDragSource); - } -} diff --git a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/metadata.json b/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/metadata.json deleted file mode 100644 index 229d3bc..0000000 --- a/dot_local/share/plasma/plasmoids/tt.launchpadPlasma/metadata.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "KPackageStructure": "Plasma/Applet", - "KPlugin": { - "Authors": [ - { - "Email": "adhemarks@gmail.com", - "Name": "Ademir" - } - ], - "BugReportUrl": "https://bugs.kde.org/enter_bug.cgi?product=plasmashell&component=Application%20Menu%20(Kicker)", - "Category": "Application Launchers", - "Description": "Configurable grid of application icons.", - "EnabledByDefault": true, - "Icon": "start-here-kde", - "Id": "tt.launchpadPlasma", - "License": "GPL-2.0+", - "Name": "Launchpad Plasma", - "Website": "https://kde.org/plasma-desktop" - }, - "X-Plasma-API-Minimum-Version": "6.0", - "X-Plasma-Provides": [ - "org.kde.plasma.launchermenu" - ] -}