diff --git a/.config/ags/assets/icons/ai-openai-symbolic.svg b/.config/ags/assets/icons/ai-openai-symbolic.svg
deleted file mode 120000
index c9ee0b32f..000000000
--- a/.config/ags/assets/icons/ai-openai-symbolic.svg
+++ /dev/null
@@ -1 +0,0 @@
-openai-symbolic.svg
\ No newline at end of file
diff --git a/.config/ags/assets/icons/ai-oxygen-symbolic.svg b/.config/ags/assets/icons/ai-oxygen-symbolic.svg
deleted file mode 100644
index 5e1cc1937..000000000
--- a/.config/ags/assets/icons/ai-oxygen-symbolic.svg
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
diff --git a/.config/ags/assets/icons/ai-zukijourney.png b/.config/ags/assets/icons/ai-zukijourney.png
deleted file mode 100644
index 917335e72..000000000
Binary files a/.config/ags/assets/icons/ai-zukijourney.png and /dev/null differ
diff --git a/.config/ags/assets/icons/arch-symbolic.svg b/.config/ags/assets/icons/arch-symbolic.svg
deleted file mode 100644
index 7de9094e0..000000000
--- a/.config/ags/assets/icons/arch-symbolic.svg
+++ /dev/null
@@ -1,113 +0,0 @@
-
-
-
-
diff --git a/.config/ags/assets/icons/cachyos-symbolic.svg b/.config/ags/assets/icons/cachyos-symbolic.svg
deleted file mode 100644
index 4a9db19ab..000000000
--- a/.config/ags/assets/icons/cachyos-symbolic.svg
+++ /dev/null
@@ -1,318 +0,0 @@
-
-
diff --git a/.config/ags/assets/icons/cloudflare-dns-symbolic.svg b/.config/ags/assets/icons/cloudflare-dns-symbolic.svg
deleted file mode 100644
index bd48d3c93..000000000
--- a/.config/ags/assets/icons/cloudflare-dns-symbolic.svg
+++ /dev/null
@@ -1,10 +0,0 @@
-
diff --git a/.config/ags/assets/icons/crosshair-symbolic.svg b/.config/ags/assets/icons/crosshair-symbolic.svg
deleted file mode 100644
index 22967493d..000000000
--- a/.config/ags/assets/icons/crosshair-symbolic.svg
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
diff --git a/.config/ags/assets/icons/debian-symbolic.svg b/.config/ags/assets/icons/debian-symbolic.svg
deleted file mode 100644
index 252f85334..000000000
--- a/.config/ags/assets/icons/debian-symbolic.svg
+++ /dev/null
@@ -1,91 +0,0 @@
-
-
-
-
diff --git a/.config/ags/assets/icons/deepseek-symbolic.svg b/.config/ags/assets/icons/deepseek-symbolic.svg
deleted file mode 100644
index 029e12663..000000000
--- a/.config/ags/assets/icons/deepseek-symbolic.svg
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
diff --git a/.config/ags/assets/icons/desktop-symbolic.svg b/.config/ags/assets/icons/desktop-symbolic.svg
deleted file mode 100644
index 04f7a3b5e..000000000
--- a/.config/ags/assets/icons/desktop-symbolic.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
diff --git a/.config/ags/assets/icons/endeavouros-symbolic.svg b/.config/ags/assets/icons/endeavouros-symbolic.svg
deleted file mode 100644
index 3be4cc406..000000000
--- a/.config/ags/assets/icons/endeavouros-symbolic.svg
+++ /dev/null
@@ -1,96 +0,0 @@
-
-
diff --git a/.config/ags/assets/icons/fedora-symbolic.svg b/.config/ags/assets/icons/fedora-symbolic.svg
deleted file mode 100644
index 1a4e8c873..000000000
--- a/.config/ags/assets/icons/fedora-symbolic.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
diff --git a/.config/ags/assets/icons/flatpak-symbolic.svg b/.config/ags/assets/icons/flatpak-symbolic.svg
deleted file mode 100644
index 0c2bf6280..000000000
--- a/.config/ags/assets/icons/flatpak-symbolic.svg
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
diff --git a/.config/ags/assets/icons/github-symbolic.svg b/.config/ags/assets/icons/github-symbolic.svg
deleted file mode 100644
index c1c9f19c4..000000000
--- a/.config/ags/assets/icons/github-symbolic.svg
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
diff --git a/.config/ags/assets/icons/google-gemini-symbolic.svg b/.config/ags/assets/icons/google-gemini-symbolic.svg
deleted file mode 100644
index 9de741be6..000000000
--- a/.config/ags/assets/icons/google-gemini-symbolic.svg
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
diff --git a/.config/ags/assets/icons/linux-symbolic.svg b/.config/ags/assets/icons/linux-symbolic.svg
deleted file mode 100644
index 63f9c7e58..000000000
--- a/.config/ags/assets/icons/linux-symbolic.svg
+++ /dev/null
@@ -1,113 +0,0 @@
-
-
-
-
diff --git a/.config/ags/assets/icons/microsoft-symbolic.svg b/.config/ags/assets/icons/microsoft-symbolic.svg
deleted file mode 100644
index b90cfc637..000000000
--- a/.config/ags/assets/icons/microsoft-symbolic.svg
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
diff --git a/.config/ags/assets/icons/nixos-symbolic.svg b/.config/ags/assets/icons/nixos-symbolic.svg
deleted file mode 100644
index b697b0d1a..000000000
--- a/.config/ags/assets/icons/nixos-symbolic.svg
+++ /dev/null
@@ -1,77 +0,0 @@
-
-
diff --git a/.config/ags/assets/icons/ollama-symbolic.svg b/.config/ags/assets/icons/ollama-symbolic.svg
deleted file mode 100644
index 014548151..000000000
--- a/.config/ags/assets/icons/ollama-symbolic.svg
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
diff --git a/.config/ags/assets/icons/openai-symbolic.svg b/.config/ags/assets/icons/openai-symbolic.svg
deleted file mode 100644
index 8ffc912ae..000000000
--- a/.config/ags/assets/icons/openai-symbolic.svg
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
diff --git a/.config/ags/assets/icons/openrouter-symbolic.svg b/.config/ags/assets/icons/openrouter-symbolic.svg
deleted file mode 100644
index 32aaaf50b..000000000
--- a/.config/ags/assets/icons/openrouter-symbolic.svg
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
diff --git a/.config/ags/assets/icons/ubuntu-symbolic.svg b/.config/ags/assets/icons/ubuntu-symbolic.svg
deleted file mode 100644
index 07746c9f6..000000000
--- a/.config/ags/assets/icons/ubuntu-symbolic.svg
+++ /dev/null
@@ -1,85 +0,0 @@
-
-
-
-
diff --git a/.config/ags/assets/images/default_wallpaper.png b/.config/ags/assets/images/default_wallpaper.png
deleted file mode 100644
index 77d890c21..000000000
Binary files a/.config/ags/assets/images/default_wallpaper.png and /dev/null differ
diff --git a/.config/ags/assets/themes/sourceviewtheme-dark-monokai-license.txt b/.config/ags/assets/themes/sourceviewtheme-dark-monokai-license.txt
deleted file mode 100644
index d159169d1..000000000
--- a/.config/ags/assets/themes/sourceviewtheme-dark-monokai-license.txt
+++ /dev/null
@@ -1,339 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Lesser General Public License instead.) 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
-this service 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 make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. 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.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-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
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the 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 a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE 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.
-
- 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
-convey 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 2 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, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) year name of author
- Gnomovision 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, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- , 1 April 1989
- Ty Coon, President of Vice
-
-This 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.
diff --git a/.config/ags/assets/themes/sourceviewtheme-light.xml b/.config/ags/assets/themes/sourceviewtheme-light.xml
deleted file mode 100644
index c880404dc..000000000
--- a/.config/ags/assets/themes/sourceviewtheme-light.xml
+++ /dev/null
@@ -1,95 +0,0 @@
-
-
- end_4
- <_description>Catppuccin port but very random
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.config/ags/assets/themes/sourceviewtheme.xml b/.config/ags/assets/themes/sourceviewtheme.xml
deleted file mode 100644
index ef76a7414..000000000
--- a/.config/ags/assets/themes/sourceviewtheme.xml
+++ /dev/null
@@ -1,121 +0,0 @@
-
-
-
-
-
-
- Leo Iannacone
- <_description>Based on SublimeText Monokai Extended - Generated with tm2gtksw2
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.config/ags/config.js b/.config/ags/config.js
deleted file mode 100644
index 73e57b57f..000000000
--- a/.config/ags/config.js
+++ /dev/null
@@ -1,81 +0,0 @@
-"use strict";
-// Import
-import Gdk from 'gi://Gdk';
-import GLib from 'gi://GLib';
-import App from 'resource:///com/github/Aylur/ags/app.js'
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'
-// Stuff
-import userOptions from './modules/.configuration/user_options.js';
-import { firstRunWelcome, startBatteryWarningService } from './services/messages.js';
-import { startAutoDarkModeService } from './services/darkmode.js';
-// Widgets
-import { Bar, BarCornerTopleft, BarCornerTopright } from './modules/bar/main.js';
-import Cheatsheet from './modules/cheatsheet/main.js';
-// import DesktopBackground from './modules/desktopbackground/main.js';
-import Dock from './modules/dock/main.js';
-import Corner from './modules/screencorners/main.js';
-import Crosshair from './modules/crosshair/main.js';
-import Indicator from './modules/indicators/main.js';
-import Osk from './modules/onscreenkeyboard/main.js';
-import Overview from './modules/overview/main.js';
-import Session from './modules/session/main.js';
-import SideLeft from './modules/sideleft/main.js';
-import SideRight from './modules/sideright/main.js';
-import { COMPILED_STYLE_DIR } from './init.js';
-
-const range = (length, start = 1) => Array.from({ length }, (_, i) => i + start);
-function forMonitors(widget) {
- const n = Gdk.Display.get_default()?.get_n_monitors() || 1;
- return range(n, 0).map(widget).flat(1);
-}
-function forMonitorsAsync(widget) {
- const n = Gdk.Display.get_default()?.get_n_monitors() || 1;
- return range(n, 0).forEach((n) => widget(n).catch(print))
-}
-
-// Start stuff
-handleStyles(true);
-startAutoDarkModeService().catch(print);
-firstRunWelcome().catch(print);
-startBatteryWarningService().catch(print)
-
-const Windows = () => [
- // forMonitors(DesktopBackground),
- forMonitors(Crosshair),
- Overview(),
- forMonitors(Indicator),
- forMonitors(Cheatsheet),
- SideLeft(),
- SideRight(),
- forMonitors(Osk),
- forMonitors(Session),
- ...(userOptions.dock.enabled ? [forMonitors(Dock)] : []),
- ...(userOptions.appearance.fakeScreenRounding !== 0 ? [
- forMonitors((id) => Corner(id, 'top left', true)),
- forMonitors((id) => Corner(id, 'top right', true)),
- forMonitors((id) => Corner(id, 'bottom left', true)),
- forMonitors((id) => Corner(id, 'bottom right', true)),
- ] : []),
- ...(userOptions.appearance.barRoundCorners ? [
- forMonitors(BarCornerTopleft),
- forMonitors(BarCornerTopright),
- ] : []),
-];
-
-const CLOSE_ANIM_TIME = 210; // Longer than actual anim time to make sure widgets animate fully
-const closeWindowDelays = {}; // For animations
-for (let i = 0; i < (Gdk.Display.get_default()?.get_n_monitors() || 1); i++) {
- closeWindowDelays[`osk${i}`] = CLOSE_ANIM_TIME;
-}
-
-App.config({
- css: `${COMPILED_STYLE_DIR}/style.css`,
- stackTraceOnError: true,
- closeWindowDelay: closeWindowDelays,
- windows: Windows().flat(1),
-});
-
-// Stuff that don't need to be toggled. And they're async so ugh...
-forMonitorsAsync(Bar);
-// Bar().catch(print); // Use this to debug the bar. Single monitor only.
-
diff --git a/.config/ags/config_overviewOnly.js b/.config/ags/config_overviewOnly.js
deleted file mode 100644
index 9c42aaa1b..000000000
--- a/.config/ags/config_overviewOnly.js
+++ /dev/null
@@ -1,24 +0,0 @@
-// Want only the overview from my config? this is what you're looking for!
-// Remember to install: `dart-sass`, `ags`, `material-symbols`, and `xorg-xrandr`
-// To launch this, run the following
-// ags -c ~/.config/ags/config_overviewOnly.js
-// To toggle the overview, run:
-// ags -t overview
-// You might wanna add that as a keybind (in hyprland.conf)
-// bind = Super, Tab, exec, ags -t overview
-
-// Import
-import App from 'resource:///com/github/Aylur/ags/app.js'
-// Widgets
-import Overview from './modules/overview/main.js';
-import { COMPILED_STYLE_DIR } from './init.js';
-
-handleStyles(true);
-
-App.config({
- css: `${COMPILED_STYLE_DIR}/style.css`,
- stackTraceOnError: true,
- windows: [
- Overview(),
- ],
-});
diff --git a/.config/ags/i18n/i18n.js b/.config/ags/i18n/i18n.js
deleted file mode 100644
index abb38a9b4..000000000
--- a/.config/ags/i18n/i18n.js
+++ /dev/null
@@ -1,55 +0,0 @@
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-import configOptions from "../modules/.configuration/user_options.js";
-const { langCode, Extra_logs } = configOptions.i18n
-const translations = {};
-
-let currentLanguage = langCode || getLanguageCode();
-
-function getLanguageCode() {
- let langEnv = GLib.getenv('LANG') || GLib.getenv('LANGUAGE') || 'Default.';
- let langCode = langEnv.split('.')[0];
- return langCode;
-}
-
-// Load language file
-function loadLanguage(lang) {
- if (!translations[lang]) {
- try {
- let filePath = `~/.config/ags/i18n/locales/${lang}.json`;
- filePath = filePath.replace(/^~/, GLib.get_home_dir());
- let file = Gio.File.new_for_path(filePath);
- let [success, contents] = file.load_contents(null);
- if (success) {
- let decoder = new TextDecoder('utf-8');
- let jsonString = decoder.decode(contents);
- translations[lang] = JSON.parse(jsonString);
- }
- } catch (error) {
- if (Extra_logs || lang === "Default")
- console.warn(`Failed to load language file, language code: ${lang}:\n`, error);
- return;
- }
- }
- currentLanguage = currentLanguage || lang;
-}
-
-// Initialize default language
-function init() {
- try {
- loadLanguage(currentLanguage);
- if (Extra_logs)
- console.log(getString("Initialization complete!") || "Initialization complete!");
- loadLanguage("Default");
- } catch (error) {
- console.error('Failed to initialize default language:', error);
- }
-}
-
-// Get translation, if no corresponding value, return the key
-function getString(key) {
- if (key && !translations[currentLanguage]?.[key] && Extra_logs)
- console.warn(`${translations[currentLanguage]["Not found"] || "Not found"}:::${key}`);
- return translations[currentLanguage]?.[key] || translations['Default']?.[key] || key;
-}
-export { getString, init };
\ No newline at end of file
diff --git a/.config/ags/i18n/locales/Default.json b/.config/ags/i18n/locales/Default.json
deleted file mode 100644
index 4b1debd6c..000000000
--- a/.config/ags/i18n/locales/Default.json
+++ /dev/null
@@ -1,250 +0,0 @@
-{
- "No media": "No media",
- "Powered by Google": "Powered by Google",
- "Not affiliated, endorsed, or sponsored by Google.\n\nPrivacy: Chat messages aren't linked to your account,\nbut will be read by human reviewers to improve the model.": "Not affiliated, endorsed, or sponsored by Google.\n\nPrivacy: Chat messages aren't linked to your account,\nbut will be read by human reviewers to improve the model.",
- "Precise": "Precise",
- "Balanced": "Balanced",
- "Creative": "Creative",
- "Gemini's temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1": "Gemini's temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1",
- "Enhancements": "Enhancements",
- "Tells Gemini:\n- It's a Linux sidebar assistant\n- Be brief and use bullet points": "Tells Gemini:\n- It's a Linux sidebar assistant\n- Be brief and use bullet points",
- "Safety": "Safety",
- "When turned off, tells the API (not the model) \nto not block harmful/explicit content": "When turned off, tells the API (not the model) \nto not block harmful/explicit content",
- "History": "History",
- "Saves chat history\nMessages in previous chats won't show automatically, but they are there": "Saves chat history\nMessages in previous chats won't show automatically, but they are there",
- "Key stored in:": "Key stored in:",
- "To update this key, type": "To update this key, type",
- "Updated API Key at": "Updated API Key at",
- "Currently using": "Currently using",
- "Select ChatGPT-compatible API provider": "Select ChatGPT-compatible API provider",
- "Official OpenAI API.\nPricing: Free for the first $5 or 3 months, whichever is less.": "Official OpenAI API.\nPricing: Free for the first $5 or 3 months, whichever is less.",
- "Official Ollama API.\nPricing: Free.": "Official Ollama API.\nPricing: Free.",
- "A unified interface for LLMs": "A unified interface for LLMs",
- "An API from Tornado Softwares\nPricing: Free: 100/day\nRequires you to join their Discord for a key": "An API from Tornado Softwares\nPricing: Free: 100/day\nRequires you to join their Discord for a key",
- "An API from @zukixa on GitHub.\nNote: Keys are IP-locked so it's buggy sometimes\nPricing: Free: 10/min, 800/day.\nRequires you to join their Discord for a key": "An API from @zukixa on GitHub.\nNote: Keys are IP-locked so it's buggy sometimes\nPricing: Free: 10/min, 800/day.\nRequires you to join their Discord for a key",
- "Provider shown above": "Provider shown above",
- "Chat with models compatible with OpenAI's Chat Completions API.\nNot affiliated, endorsed, or sponsored by any of the providers.": "Chat with models compatible with OpenAI's Chat Completions API.\nNot affiliated, endorsed, or sponsored by any of the providers.",
- "The model's temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1": "The model's temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1",
- "An API key is required\nYou can grab one here, then enter it below": "An API key is required\nYou can grab one here, then enter it below",
- "Tells the model:\n- It's a Linux sidebar assistant\n- Be brief and use bullet points": "Tells the model:\n- It's a Linux sidebar assistant\n- Be brief and use bullet points",
- "Powered by waifu.im + other APIs": "Powered by waifu.im + other APIs",
- "Type tags for a random pic.\nNSFW content will not be returned unless\nyou explicitly request such a tag.\n\nDisclaimer: Not affiliated with the providers\nnor responsible for any of their content.": "Type tags for a random pic.\nNSFW content will not be returned unless\nyou explicitly request such a tag.\n\nDisclaimer: Not affiliated with the providers\nnor responsible for any of their content.",
- "Tags →": "Tags →",
- "Invalid command.": "Invalid command.",
- "Anime booru": "Anime booru",
- "Powered by yande.re and konachan": "Powered by yande.re and konachan",
- "An image booru. May contain NSFW content.\nWatch your back.\n\nDisclaimer: Not affiliated with the provider\nnor responsible for any of its content.": "An image booru. May contain NSFW content.\nWatch your back.\n\nDisclaimer: Not affiliated with the provider\nnor responsible for any of its content.",
- "Lewds": "Lewds",
- "Shows naughty stuff when enabled": "Shows naughty stuff when enabled",
- "Saves images in folders by their tags": "Saves images in folders by their tags",
- "Message Gemini...": "Message Gemini...",
- "Enter Google AI API Key...": "Enter Google AI API Key...",
- "Message the model...": "Message the model...",
- "Enter API Key...": "Enter API Key...",
- "Enter tags": "Enter tags",
- "Enter tags and/or page number": "Enter tags and/or page number",
- "No tag in mind? Type a page number": "No tag in mind? Type a page number",
- "Quick scripts": "Quick scripts",
- "Change screen resolution": "Change screen resolution",
- "Update packages": "Update packages",
- "Trim system generations to 5": "Trim system generations to 5",
- "Trim home manager generations to 5": "Trim home manager generations to 5",
- "Remove orphan packages": "Remove orphan packages",
- "Uninstall unused flatpak packages": "Uninstall unused flatpak packages",
- "Inaccurate Color picker": "Inaccurate Color picker",
- "Result": "Result",
- "Type to search": "Type to search",
- "illogical-impulse": "illogical-impulse",
- "RAM Usage": "RAM Usage",
- "Swap Usage": "Swap Usage",
- "CPU Usage": "CPU Usage",
- "Uptime:": "Uptime:",
- "Screen snip": "Screen snip",
- "Color picker": "Color picker",
- "Toggle on-screen keyboard": "Toggle on-screen keyboard",
- "Night Light": "Night Light",
- "Color inversion": "Color inversion",
- "Keep system awake": "Keep system awake",
- "Cloudflare WARP": "Cloudflare WARP",
- "Session": "Session",
- "Bluetooth | Right-click to configure": "Bluetooth | Right-click to configure",
- "Wifi | Right-click to configure": "Wifi | Right-click to configure",
- "Right-click to configure": "Right-click to configure",
- "Unknown": "Unknown",
- "Reload Environment config": "Reload Environment config",
- "Open Settings": "Open Settings",
- "Notifications": "Notifications",
- "Audio controls": "Audio controls",
- "Bluetooth": "Bluetooth",
- "Wifi networks": "Wifi networks",
- "Quick config": "Quick config",
- "Silence": "Silence",
- "Clear": "Clear",
- "No notifications": "No notifications",
- "notifications": "notifications",
- "Close": "Close",
- "Now": "Now",
- "Yesterday": "Yesterday",
- "No audio source": "No audio source",
- "Remove device": "Remove device",
- "Connected": "Connected",
- "Paired": "Paired",
- "More": "More",
- "Selected": "Selected",
- "Connecting to": "Connecting to",
- "Current network": "Current network",
- "Authentication": "Authentication",
- "Authentication failed": "Authentication failed",
- "Enter network password": "Enter network password",
- "Properties": "Properties",
- "Forget": "Forget",
- "Effects": "Effects",
- "Transparency": "Transparency",
- "[AGS]\nMake shell elements transparent\nBlur is also recommended if you enable this": "[AGS]\nMake shell elements transparent\nBlur is also recommended if you enable this",
- "Blur": "Blur",
- "[Hyprland]\nEnable blur on transparent elements\nDoesn't affect performance/power consumption unless you have transparent windows.": "[Hyprland]\nEnable blur on transparent elements\nDoesn't affect performance/power consumption unless you have transparent windows.",
- "X-ray": "X-ray",
- "[Hyprland]\nMake everything behind a window/layer except the wallpaper not rendered on its blurred surface\nRecommended to improve performance (if you don't abuse transparency/blur) ": "[Hyprland]\nMake everything behind a window/layer except the wallpaper not rendered on its blurred surface\nRecommended to improve performance (if you don't abuse transparency/blur) ",
- "Size": "Size",
- "[Hyprland]\nAdjust the blur radius. Generally doesn't affect performance\nHigher = more color spread": "[Hyprland]\nAdjust the blur radius. Generally doesn't affect performance\nHigher = more color spread",
- "Passes": "Passes",
- "[Hyprland] Adjust the number of runs of the blur algorithm\nMore passes = more spread and power consumption\n4 is recommended\n2- would look weird and 6+ would look lame.": "[Hyprland] Adjust the number of runs of the blur algorithm\nMore passes = more spread and power consumption\n4 is recommended\n2- would look weird and 6+ would look lame.",
- "Animations": "Animations",
- "[Hyprland] [GTK]\nEnable animations": "[Hyprland] [GTK]\nEnable animations",
- "Choreography delay": "Choreography delay",
- "In milliseconds, the delay between animations of a series": "In milliseconds, the delay between animations of a series",
- "Developer": "Developer",
- "Show FPS": "Show FPS",
- "[Hyprland]\nShow FPS overlay on top-left corner": "[Hyprland]\nShow FPS overlay on top-left corner",
- "Log to stdout": "Log to stdout",
- "[Hyprland]\nPrint LOG, ERR, WARN, etc. messages to the console": "[Hyprland]\nPrint LOG, ERR, WARN, etc. messages to the console",
- "Damage tracking": "Damage tracking",
- "[Hyprland]\nEnable damage tracking\nGenerally, leave it on.\nTurn off only when a shader doesn't work": "[Hyprland]\nEnable damage tracking\nGenerally, leave it on.\nTurn off only when a shader doesn't work",
- "Damage blink": "Damage blink",
- "[Hyprland] [Epilepsy warning!]\nShow screen damage flashes": "[Hyprland] [Epilepsy warning!]\nShow screen damage flashes",
- "Not all changes are saved": "Not all changes are saved",
- "Mo": "Mo",
- "Tu": "Tu",
- "We": "We",
- "Th": "Th",
- "Fr": "Fr",
- "Sa": "Sa",
- "Su": "Su",
- "Calendar": "Calendar",
- "To Do": "To Do",
- "Unfinished": "Unfinished",
- "Done": "Done",
- "Finished tasks will go here": "Finished tasks will go here",
- "Nothing here!": "Nothing here!",
- "+ New task": "+ New task",
- "Add a task...": "Add a task...",
- "Collapse calendar": "Collapse calendar",
- "Expand calendar": "Expand calendar",
- "To do tasks": "To do tasks",
- "Color scheme": "Color scheme",
- "Options": "Options",
- "Dark Mode": "Dark Mode",
- "Ya should go to sleep!": "Ya should go to sleep!",
- "Theme GTK apps using accent color\n(drawback: dark/light mode switching requires restart)": "Theme GTK apps using accent color\n(drawback: dark/light mode switching requires restart)",
- "Scheme styles": "Scheme styles",
- "Vibrant": "Vibrant",
- "Vibrant+": "Vibrant+",
- "Expressive": "Expressive",
- "Monochrome": "Monochrome",
- "Rainbow": "Rainbow",
- "Fidelity": "Fidelity",
- "Fruit Salad": "Fruit Salad",
- "Tonal Spot": "Tonal Spot",
- "Content": "Content",
- "Use arrow keys to navigate.\nEnter to select, Esc to cancel.": "Use arrow keys to navigate.\nEnter to select, Esc to cancel.",
- "Lock": "Lock",
- "Logout": "Logout",
- "Sleep": "Sleep",
- "Hibernate": "Hibernate",
- "Shutdown": "Shutdown",
- "Reboot": "Reboot",
- "Cancel": "Cancel",
- "Cheat sheet": "Cheat sheet",
- "Keybinds": "Keybinds",
- "Periodic table": "Periodic table",
- "Essentials for beginners": "Essentials for beginners",
- "Make shell elements transparent": "Make shell elements transparent",
- "Actions": "Actions",
- "Window management": "Window management",
- "Window arrangement": "Window arrangement",
- "Workspace management": "Workspace management",
- "Workspace navigation": "Workspace navigation",
- "Widgets": "Widgets",
- "Media": "Media",
- "Apps": "Apps",
- "Neutral": "Neutral",
- "Launch foot (terminal)": "Launch foot (terminal)",
- "Open app launcher": "Open app launcher",
- "Change wallpaper": "Change wallpaper",
- "Clipboard history >> clipboard": "Clipboard history >> clipboard",
- "Pick emoji >> clipboard": "Pick emoji >> clipboard",
- "Screen snip >> edit": "Screen snip >> edit",
- "Screen snip to text >> clipboard": "Screen snip to text >> clipboard",
- "Pick color (Hex) >> clipboard": "Pick color (Hex) >> clipboard",
- "Screenshot >> clipboard": "Screenshot >> clipboard",
- "Screenshot >> clipboard & file": "Screenshot >> clipboard & file",
- "Record region (no sound)": "Record region (no sound)",
- "Record screen (with sound)": "Record screen (with sound)",
- "Suspend system": "Suspend system",
- "Move focus in direction": "Move focus in direction",
- "Move window": "Move window",
- "Resize window": "Resize window",
- "Close window": "Close window",
- "Pick and kill a window": "Pick and kill a window",
- "Window: move in direction": "Window: move in direction",
- "Window: split ratio +/- 0.1": "Window: split ratio +/- 0.1",
- "Float/unfloat window": "Float/unfloat window",
- "Toggle fake fullscreen": "Toggle fake fullscreen",
- "Toggle fullscreen": "Toggle fullscreen",
- "Toggle maximization": "Toggle maximization",
- "Focus workspace # (1, 2, 3, 4, ...)": "Focus workspace # (1, 2, 3, 4, ...)",
- "Workspace: focus left/right": "Workspace: focus left/right",
- "Workspace: toggle special": "Workspace: toggle special",
- "Window: move to workspace # (1, 2, 3, 4, ...)": "Window: move to workspace # (1, 2, 3, 4, ...)",
- "Window: move to workspace left/right": "Window: move to workspace left/right",
- "Window: move to workspace special": "Window: move to workspace special",
- "Window: pin (show on all workspaces)": "Window: pin (show on all workspaces)",
- "Restart widgets": "Restart widgets",
- "Cycle bar mode (normal, focus)": "Cycle bar mode (normal, focus)",
- "Toggle overview/launcher": "Toggle overview/launcher",
- "Show cheatsheet": "Show cheatsheet",
- "Toggle left sidebar": "Toggle left sidebar",
- "Toggle right sidebar": "Toggle right sidebar",
- "Toggle music controls": "Toggle music controls",
- "View color scheme and options": "View color scheme and options",
- "Toggle power menu": "Toggle power menu",
- "Toggle crosshair": "Toggle crosshair",
- "Next track": "Next track",
- "Previous track": "Previous track",
- "Play/pause media": "Play/pause media",
- "Launch Zed (editor)": "Launch Zed (editor)",
- "Launch VSCode (editor)": "Launch VSCode (editor)",
- "Launch Nautilus (file manager)": "Launch Nautilus (file manager)",
- "Launch Firefox (browser)": "Launch Firefox (browser)",
- "Launch GNOME Text Editor": "Launch GNOME Text Editor",
- "Launch WPS Office": "Launch WPS Office",
- "Launch GNOME Settings": "Launch GNOME Settings",
- "Launch pavucontrol (volume mixer)": "Launch pavucontrol (volume mixer)",
- "Launch EasyEffects (equalizer & other audio effects)": "Launch EasyEffects (equalizer & other audio effects)",
- "Launch GNOME System monitor": "Launch GNOME System monitor",
- "Toggle fallback launcher: anyrun": "Toggle fallback launcher: anyrun",
- "Toggle fallback launcher: fuzzel": "Toggle fallback launcher: fuzzel",
- "Initialization complete!": "Initialization complete!",
- "Not found": "Not found:",
- "Calling API": "Calling API",
- "Downloading image": "Downloading image",
- "Finished!": "Finished!",
- "Error": "Error",
- "Not found!": "Not found!",
- "Go to file url": "Go to file url",
- "Save image": "Save image",
- "Hoard": "Hoard",
- "Open externally": "Open externally",
- "You are an assistant on a sidebar of a Wayland Linux desktop. Please always use a casual tone when answering your questions, unless requested otherwise or making writing suggestions. These are the steps you should take to respond to the user's queries:\n1. If it's a writing- or grammar-related question or a sentence in quotation marks, Please point out errors and correct when necessary using underlines, and make the writing more natural where appropriate without making too major changes. If you're given a sentence in quotes but is grammatically correct, explain briefly concepts that are uncommon.\n2. If it's a question about system tasks, give a bash command in a code block with brief explanation.\n3. Otherwise, when asked to summarize information or explaining concepts, you are should use bullet points and headings. For mathematics expressions, you *have to* use LaTeX within a code block with the language set as \"latex\". \nNote: Use casual language, be short, while ensuring the factual correctness of your response. If you are unsure or don’t have enough information to provide a confident answer, simply say “I don’t know” or “I’m not sure.”. \nThanks!": "You are an assistant on a sidebar of a Wayland Linux desktop. Please always use a casual tone when answering your questions, unless requested otherwise or making writing suggestions. These are the steps you should take to respond to the user's queries:\n1. If it's a writing- or grammar-related question or a sentence in quotation marks, Please point out errors and correct when necessary using underlines, and make the writing more natural where appropriate without making too major changes. If you're given a sentence in quotes but is grammatically correct, explain briefly concepts that are uncommon.\n2. If it's a question about system tasks, give a bash command in a code block with brief explanation.\n3. Otherwise, when asked to summarize information or explaining concepts, you are should use bullet points and headings. For mathematics expressions, you *have to* use LaTeX within a code block with the language set as \"latex\". \nNote: Use casual language, be short, while ensuring the factual correctness of your response. If you are unsure or don’t have enough information to provide a confident answer, simply say “I don’t know” or “I’m not sure.”. \nThanks!",
- "Feels like": "Feels like"
-}
diff --git a/.config/ags/i18n/locales/fa_IR.json b/.config/ags/i18n/locales/fa_IR.json
deleted file mode 100644
index 1ff44b553..000000000
--- a/.config/ags/i18n/locales/fa_IR.json
+++ /dev/null
@@ -1,238 +0,0 @@
-{
- "No media": "بدون رسانه",
- "Powered by Google": "قدرت گرفته از گوگل",
- "Not affiliated, endorsed, or sponsored by Google.\n\nPrivacy: Chat messages aren't linked to your account,\nbut will be read by human reviewers to improve the model.": "بدون وابستگی تأیید شده یا حمایت شده توسط گوگل.\n\nحریم خصوصی: پیامهای گفتگو به حساب شما مرتبط نیستند،\nاما توسط بازبینیکنندگان انسانی برای بهبود مدل خوانده خواهند شد.",
- "Precise": "دقیق",
- "Balanced": "متعادل",
- "Creative": "خلاق",
- "Gemini's temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1": "مقدار دما در Gemini.\n دقیق = 0\n متعادل = 0.5\n خلاق = 1",
- "Enhancements": "بهبودها",
- "Tells Gemini:\n- It's a Linux sidebar assistant\n- Be brief and use bullet points": "به Gemini میگوید:\n- این یک دستیار نوار کناری لینوکس است\n- مختصر باشید و از فهرست کردن کمک بگیرید",
- "Safety": "ایمنی",
- "When turned off, tells the API (not the model) \nto not block harmful/explicit content": "زمانی که خاموش باشد، به API (نه مدل) میگوید که \nمحتوای مضر/صریح را مسدود نکند",
- "History": "پیشینه",
- "Saves chat history\nMessages in previous chats won't show automatically, but they are there": "پیشینه گفتگو را نگهداری میکند\nپیامهای گفتگوهای پیشین بهطور خودکار نمایش داده نمیشوند، اما وجود دارند",
- "Key stored in:": "کلید نگهداری شده در:",
- "To update this key, type": "برای بهروزرسانی این کلید، بنویسید",
- "Updated API Key at": "کلید API بهروزرسانی شده در",
- "Currently using": "هماینک بکار گرفته میشود",
- "Select ChatGPT-compatible API provider": "انتخاب ارائهدهنده API سازگار با ChatGPT",
- "Official OpenAI API.\nPricing: Free for the first $5 or 3 months, whichever is less.": "API رسمی OpenAI.\nقیمتگذاری: رایگان برای اولین 5 دلار یا 3 ماه، هر کدام که کمتر باشد.",
- "Official Ollama API.\nPricing: Free.": "API رسمی Ollama.\nقیمتگذاری: رایگان.",
- "A unified interface for LLMs": "یک رابط یکپارچه برای LLMها",
- "An API from Tornado Softwares\nPricing: Free: 100/day\nRequires you to join their Discord for a key": "API از Tornado Softwares\nقیمتگذاری: رایگان: 100 در روز\nنیاز به پیوستن به دیسکورد آنها برای دریافت کلید دارد",
- "An API from @zukixa on GitHub.\nNote: Keys are IP-locked so it's buggy sometimes\nPricing: Free: 10/min, 800/day.\nRequires you to join their Discord for a key": "API از @zukixa در گیتهاب.\nتوجه: کلیدها قفل IP هستند بنابراین گاهی اوقات باگ دارند\nقیمتگذاری: رایگان: 10 در دقیقه، 800 در روز.\nنیاز به پیوستن به دیسکورد آنها برای دریافت کلید دارد",
- "Provider shown above": "ارائهدهنده در بالا نشان داده شده است",
- "The model's temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1": "مقدار دما در مدل.\n دقیق = 0\n متعادل = 0.5\n خلاق = 1",
- "An API key is required\nYou can grab one here, then enter it below": "یک کلید API مورد نیاز است\nشما میتوانید یکی را اینجا بگیرید، سپس آن را پایین وارد کنید",
- "Tells the model:\n- It's a Linux sidebar assistant\n- Be brief and use bullet points": "به مدل میگوید:\n- این یک دستیار نوار کناری لینوکس است\n- گزافهگو نباشید و نقاط فهرست بکار ببرید",
- "Powered by waifu.im + other APIs": "قدرت گرفته از waifu.im + سایر APIها",
- "Type tags for a random pic.\nNSFW content will not be returned unless\nyou explicitly request such a tag.\n\nDisclaimer: Not affiliated with the providers\nnor responsible for any of their content.": "برچسبها را برای یک تصویر تصادفی بنویسید.\nمحتوای NSFW بازگردانده نخواهد شد مگر اینکه\nشما بهطور صریح چنین برچسبی را درخواست کنید.\n\nتوجه: بدون وابستگی ارائهدهندگان\nو مسئول هیچیک از محتوای آنها نیست.",
- "Tags →": "برچسبها →",
- "Invalid command.": "دستور نامعتبر.",
- "Anime booru": "انیمه بورو",
- "Powered by yande.re and konachan": "قدرت گرفته از yande.re و konachan",
- "An image booru. May contain NSFW content.\nWatch your back.\n\nDisclaimer: Not affiliated with the provider\nnor responsible for any of its content.": "یک تصویر بورو. ممکن است محتوای NSFW داشته باشد.\nمواظب باشید.\n\nتوجه: بدون وابستگی به ارائهدهنده\nو مسئول هیچیک از محتوای آن نیست.",
- "Lewds": "محتوای نامناسب",
- "Shows naughty stuff when enabled": "محتوای نامناسب را زمانی که فعال باشد نشان میدهد",
- "Saves images in folders by their tags": "تصاویر را در پوشهها بر اساس برچسبهایشان نگهداری میکند",
- "Message Gemini...": "پیام به Gemini...",
- "Enter Google AI API Key...": "کلید API گوگل AI را وارد کنید...",
- "Message the model...": "پیام به مدل...",
- "Enter API Key...": "کلید API را وارد کنید...",
- "Enter tags": "برچسبها را وارد کنید",
- "Quick scripts": "اسکریپتهای سریع",
- "Change screen resolution": "تغییر وضوح صفحه",
- "Update packages": "بهروزرسانی بستهها",
- "Trim system generations to 5": "تعداد نسلهای سامانه را به 5 کاهش دهید",
- "Trim home manager generations to 5": "تعداد نسلهای مدیر خانه را به 5 کاهش دهید",
- "Remove orphan packages": "بستههای ناکارآمد را پاک کنید",
- "Uninstall unused flatpak packages": "بستههای فلتپک بکار گرفته نشده را پاک کنید",
- "Inaccurate Color picker": "نادرست انتخابگر رنگ",
- "Result": "نتیجه",
- "Type to search": "برای جستجو بنویسید",
- "illogical-impulse": "illogical-impulse",
- "RAM Usage": "کارکرد RAM",
- "Swap Usage": "کارکرد Swap",
- "CPU Usage": "کارکرد CPU",
- "Uptime:": "در حال کار:",
- "Screen snip": "برش صفحه",
- "Color picker": "انتخابگر رنگ",
- "Toggle on-screen keyboard": "کیبورد روی صفحه را فعال/غیرفعال کنید",
- "Night Light": "نور شب",
- "Color inversion": "وارونگی رنگ",
- "Keep system awake": "سامانه را بیدار نگهدارید",
- "Cloudflare WARP": "Cloudflare WARP",
- "Session": "نشست",
- "Bluetooth | Right-click to configure": "بلوتوث | برای پیکربندی راست کلیک کنید ",
- "Wifi | Right-click to configure": "وایفای | برای پیکربندی راست کلیک کنید ",
- "Right-click to configure": "برای پیکربندی راست کلیک کنید",
- "Unknown": "ناشناخته",
- "Reload Environment config": "پیکربندی محیط را دوباره بارگذاری کنید",
- "Open Settings": "تنظیمات را باز کنید",
- "Notifications": "آگاهسازها",
- "Audio controls": "کنترلهای صدا",
- "Bluetooth": "بلوتوث",
- "Wifi networks": "شبکههای وایفای",
- "Quick config": "پیکربندی زنده",
- "Silence": "سکوت",
- "Clear": "پاک کردن",
- "No notifications": "بدون آگاهساز",
- "notifications": "آگاهسازها",
- "Close": "بستن",
- "Now": "اینک",
- "Yesterday": "دیروز",
- "No audio source": "هیچ منبع صوتی",
- "Remove device": "پاککردن دستگاه",
- "Connected": "متصل",
- "Paired": "جفت شده",
- "More": "بیشتر",
- "Selected": "انتخاب شده",
- "Current network": "شبکه کنونی",
- "Authentication": "احراز هویت",
- "Effects": "جلوهها",
- "Transparency": "شفافیت",
- "[AGS]\nMake shell elements transparent\nBlur is also recommended if you enable this": "[AGS]\nعناصر شل را شفاف کنید\nهمچنین اگر این را فعال کنید، تاری نیز توصیه میشود",
- "Blur": "تاری",
- "[Hyprland]\nEnable blur on transparent elements\nDoesn't affect performance/power consumption unless you have transparent windows.": "[Hyprland]\nفعال کردن تاری بر روی عناصر شفاف\nبر عملکرد/مصرف برق تأثیر نمیگذارد مگر اینکه پنجرههای شفاف داشته باشید.",
- "X-ray": "اشعه ایکس",
- "[Hyprland]\nMake everything behind a window/layer except the wallpaper not rendered on its blurred surface\nRecommended to improve performance (if you don't abuse transparency/blur) ": "[Hyprland]\nهمه چیز را پشت یک پنجره/لایه به جز پسزمینه بر روی سطح تاری آن رندر نکنید\nتوصیه میشود برای بهبود عملکرد (اگر از شفافیت/تاری سوءاستفاده نکنید)",
- "Size": "اندازه",
- "[Hyprland]\nAdjust the blur radius. Generally doesn't affect performance\nHigher = more color spread": "[Hyprland]\nشعاع تاری را تنظیم کنید. به طور کلی بر عملکرد تأثیر نمیگذارد\nبیشتر = پخش رنگ بیشتر",
- "Passes": "عبور",
- "[Hyprland] Adjust the number of runs of the blur algorithm\nMore passes = more spread and power consumption\n4 is recommended\n2- would look weird and 6+ would look lame.": "[Hyprland] تعداد عبورهای الگوریتم تاری را تنظیم کنید\nعبورهای بیشتر = پخش بیشتر و مصرف برق بیشتر\n4 توصیه میشود\n2- عجیب به نظر میرسد و 6+ بیمزه خواهد بود.",
- "Animations": "پویانماییها",
- "[Hyprland] [GTK]\nEnable animations": "[Hyprland] [GTK]\nفعال کردن پویانماییها",
- "Choreography delay": "درنگ در پویایی",
- "In milliseconds, the delay between animations of a series": "به میلیثانیه، درنگ بین پویانماییهای یک سری",
- "Developer": "توسعهدهنده",
- "Show FPS": "نمایش FPS",
- "[Hyprland]\nShow FPS overlay on top-left corner": "[Hyprland]\nنمایش پوشش FPS در گوشه بالا سمت چپ",
- "Log to stdout": "ثبت در stdout",
- "[Hyprland]\nPrint LOG, ERR, WARN, etc. messages to the console": "[Hyprland]\nپیامهای LOG، ERR، WARN و دیگر را به کنسول چاپ کنید",
- "Damage tracking": "ردیابی آسیب",
- "[Hyprland]\nEnable damage tracking\nGenerally, leave it on.\nTurn off only when a shader doesn't work": "[Hyprland]\nفعال کردن ردیابی آسیب\nبه طور کلی، آن را روشن بگذارید.\nفقط زمانی که یک سایهزن(شیدر) کار نمیکند، خاموش کنید",
- "Damage blink": "چشمک آسیب",
- "[Hyprland] [Epilepsy warning!]\nShow screen damage flashes": "[Hyprland] [هشدار صرع!]\nنمایش چشمکهای آسیب صفحه",
- "Not all changes are saved": "همه تغییرات نگهداری نشدهاند",
- "Mo": "دو",
- "Tu": "سه",
- "We": "چهار",
- "Th": "پنج",
- "Fr": "جمعه",
- "Sa": "شنبه",
- "Su": "یک",
- "Calendar": "تقویم",
- "To Do": "کارها",
- "Unfinished": "مانده",
- "Done": "پایان یافته",
- "Finished tasks will go here": "کارهای پایان یافته اینجا خواهند بود",
- "Nothing here!": "هیچ چیز اینجا نیست!",
- "+ New task": "+ کار جدید",
- "Add a task...": "افزودن یک کار...",
- "Color scheme": "طرح رنگ",
- "Options": "گزینهها",
- "Dark Mode": "حالت تاریک",
- "Ya should go to sleep!": "پاشو برو بخواب!",
- "Theme GTK apps using accent color\n(drawback: dark/light mode switching requires restart)": "برنامههای GTK را با بکارگیری رنگ تأکید پوسته گذاری کنید\n(معایب: تغییر حالت تاریک/روشن نیاز به باز راهاندازی دارد)",
- "Scheme styles": "سبکهای طرح",
- "Vibrant": "زنده",
- "Vibrant+": "زنده+",
- "Expressive": "بیانگر",
- "Monochrome": "تکرنگ",
- "Rainbow": "رنگین کمان",
- "Fidelity": "وفاداری",
- "Fruit Salad": "سالاد میوه",
- "Tonal Spot": "نقطه تنال",
- "Content": "محتوا",
- "Use arrow keys to navigate.\nEnter to select, Esc to cancel.": "برای ناوبری کلیدهای جهتدار را بکار ببرید.\nبرای انتخاب Enter و برای رد کردن Esc را بزنید.",
- "Lock": "قفل",
- "Logout": "خروج",
- "Sleep": "خواب",
- "Hibernate": "خواب زمستانی",
- "Shutdown": "خاموش",
- "Reboot": "باز راهاندازی",
- "Cancel": "رد کردن",
- "Cheat sheet": "برگه تقلب",
- "Keybinds": "کلیدهای میانبر",
- "Periodic table": "جدول تناوبی",
- "Essentials for beginners": "اساس برای مبتدیان",
- "Make shell elements transparent": "عناصر شل را شفاف کنید",
- "Actions": "کنش",
- "Window management": "مدیریت پنجره",
- "Window arrangement": "چیدمان پنجره",
- "Workspace management": "مدیریت فضای کاری",
- "Workspace navigation": "ناوبری فضای کاری",
- "Widgets": "ابزارکها",
- "Media": "رسانه",
- "Apps": "برنامهها",
- "Neutral": "خنثی",
- "Launch foot (terminal)": "اجرای foot (ترمینال)",
- "Open app launcher": "باز کردن راهانداز برنامه",
- "Change wallpaper": "تغییر پسزمینه",
- "Clipboard history >> clipboard": "پیشینه کلیپ بورد >> کلیپ بورد",
- "Pick emoji >> clipboard": "انتخاب ایموجی >> کلیپ بورد",
- "Screen snip >> edit": "برش صفحه >> ویرایش",
- "Screen snip to text >> clipboard": "برش صفحه به متن >> کلیپ بورد",
- "Pick color (Hex) >> clipboard": "انتخاب رنگ (Hex) >> کلیپ بورد",
- "Screenshot >> clipboard": "عکس صفحه >> کلیپ بورد",
- "Screenshot >> clipboard & file": "عکس صفحه >> کلیپ بورد و فایل",
- "Record region (no sound)": "ضبط منطقه (بدون صدا)",
- "Record screen (with sound)": "ضبط صفحه (با صدا)",
- "Suspend system": "تعلیق سامانه",
- "Move focus in direction": "جابهجایی تمرکز در جهت",
- "Move window": "جابهجایی پنجره",
- "Resize window": "تغییر اندازه پنجره",
- "Close window": "بستن پنجره",
- "Pick and kill a window": "انتخاب و بستن یک پنجره",
- "Window: move in direction": "پنجره: جابهجایی در جهت",
- "Window: split ratio +/- 0.1": "پنجره: نسبت تقسیم +/- 0.1",
- "Float/unfloat window": "پنجره را شناور/نا شناور کنید",
- "Toggle fake fullscreen": "تغییر حالت تمام صفحه ساختگی",
- "Toggle fullscreen": "تغییر حالت تمام صفحه",
- "Toggle maximization": "تغییر حالت بزرگنمایی",
- "Focus workspace # (1, 2, 3, 4, ...)": "تمرکز بر فضای کاری # (1، 2، 3، 4، ...)",
- "Workspace: focus left/right": "فضای کاری: تمرکز به چپ/راست",
- "Workspace: toggle special": "فضای کاری: تغییر حالت خاص",
- "Window: move to workspace # (1, 2, 3, 4, ...)": "پنجره: رفتن به فضای کاری # (1، 2، 3، 4، ...)",
- "Window: move to workspace left/right": "پنجره: رفتن به فضای کاری چپ/راست",
- "Window: move to workspace special": "پنجره: رفتن به فضای کاری خاص",
- "Window: pin (show on all workspaces)": "پنجره: سنجاق (نمایش در همه فضاهای کاری)",
- "Restart widgets": "باز راهاندازی ابزارکها",
- "Cycle bar mode (normal, focus)": "چرخش حالت نوار (عادی، تمرکز)",
- "Toggle overview/launcher": "تغییر حالت نمای کلی/راهانداز",
- "Show cheatsheet": "نمایش برگه تقلب",
- "Toggle left sidebar": "تغییر حالت نوار کناری چپ",
- "Toggle right sidebar": "تغییر حالت نوار کناری راست",
- "Toggle music controls": "تغییر حالت کنترلهای موسیقی",
- "View color scheme and options": "مشاهده طرح رنگ و گزینهها",
- "Toggle power menu": "تغییر حالت فهرست قدرت",
- "Toggle crosshair": "تغییر حالت نشانهگذاری",
- "Next track": "ترانه پسین",
- "Previous track": "ترانه پیشین",
- "Play/pause media": "پخش/مکث رسانه",
- "Launch Zed (editor)": "اجرای Zed (ویرایشگر)",
- "Launch VSCode (editor)": "اجرای VSCode (ویرایشگر)",
- "Launch Nautilus (file manager)": "اجرای Nautilus (مدیر فایل)",
- "Launch Firefox (browser)": "اجرای Firefox (مرورگر)",
- "Launch GNOME Text Editor": "اجرای ویرایشگر متن GNOME",
- "Launch WPS Office": "اجرای WPS Office",
- "Launch GNOME Settings": "اجرای تنظیمات GNOME",
- "Launch pavucontrol (volume mixer)": "اجرای pavucontrol (میکسر صدا)",
- "Launch EasyEffects (equalizer & other audio effects)": "اجرای EasyEffects (اکولایزر و سایر جلوههای صوتی)",
- "Launch GNOME System monitor": "اجرای مانیتور سامانه GNOME",
- "Toggle fallback launcher: anyrun": "بکارگیری راهانداز پشتیبان: anyrun",
- "Toggle fallback launcher: fuzzel": "بکارگیری راهانداز پشتیبان: fuzzel",
- "Initialization complete!": "راهاندازی کامل شد!",
- "Not found": "یافت نشد:",
- "Calling API": "در حال تماس با API",
- "Downloading image": "در حال دریافت تصویر",
- "Finished!": "پایان یافت!",
- "Error": "خطا",
- "Not found!": "یافت نشد!",
- "Go to file url": "رفتن به URL فایل",
- "Save image": "نگهداری تصویر",
- "Hoard": "نگهداری",
- "Open externally": "باز کردن در",
- "You are an assistant on a sidebar of a Wayland Linux desktop. Please always use a casual tone when answering your questions, unless requested otherwise or making writing suggestions. These are the steps you should take to respond to the user's queries:\n1. If it's a writing- or grammar-related question or a sentence in quotation marks, Please point out errors and correct when necessary using underlines, and make the writing more natural where appropriate without making too major changes. If you're given a sentence in quotes but is grammatically correct, explain briefly concepts that are uncommon.\n2. If it's a question about system tasks, give a bash command in a code block with brief explanation.\n3. Otherwise, when asked to summarize information or explaining concepts, you are should use bullet points and headings. For mathematics expressions, you *have to* use LaTeX within a code block with the language set as \"latex\". \nNote: Use casual language, be short, while ensuring the factual correctness of your response. If you are unsure or don’t have enough information to provide a confident answer, simply say “I don’t know” or “I’m not sure.”. \nThanks!": "You are an assistant on a sidebar of a Wayland Linux desktop. Please always use a casual tone when answering your questions, unless requested otherwise or making writing suggestions. These are the steps you should take to respond to the user's queries:\n1. If it's a writing- or grammar-related question or a sentence in quotation marks, Please point out errors and correct when necessary using underlines, and make the writing more natural where appropriate without making too major changes. If you're given a sentence in quotes but is grammatically correct, explain briefly concepts that are uncommon.\n2. If it's a question about system tasks, give a bash command in a code block with brief explanation.\n3. Otherwise, when asked to summarize information or explaining concepts, you are should use bullet points and headings. For mathematics expressions, you *have to* use LaTeX within a code block with the language set as \"latex\". \nNote: Use casual language, be short, while ensuring the factual correctness of your response. If you are unsure or don’t have enough information to provide a confident answer, simply say “I don’t know” or “I’m not sure.”. \nIf user talks to you in Persian and you can also respond in Persian, definitely respond in Persian. Thanks!"
-}
diff --git a/.config/ags/i18n/locales/fr_FR.json b/.config/ags/i18n/locales/fr_FR.json
deleted file mode 100644
index 4c9a8e80f..000000000
--- a/.config/ags/i18n/locales/fr_FR.json
+++ /dev/null
@@ -1,240 +0,0 @@
-{
- "No media": "Aucun média",
- "Powered by Google": "Fourni par Google",
- "Not affiliated, endorsed, or sponsored by Google.\n\nPrivacy: Chat messages aren't linked to your account,\nbut will be read by human reviewers to improve the model.": "Non affilié, approuvé ou sponsorisé par Google.\n\nConfidentialité : Les messages de chat ne sont pas liés à votre compte,\nmais seront lus par des examinateurs humains pour améliorer le modèle.",
- "Precise": "Précis",
- "Balanced": "Équilibré",
- "Creative": "Créatif",
- "Gemini's temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1": "Température de Gemini.\n Précis = 0\n Équilibré = 0.5\n Créatif = 1",
- "Enhancements": "Améliorations",
- "Tells Gemini:\n- It's a Linux sidebar assistant\n- Be brief and use bullet points": "Indique à Gemini :\n- C'est un assistant de panneau latéral pour Linux\n- Sois concis et utilise des puces",
- "Safety": "Sécurité",
- "When turned off, tells the API (not the model) \nto not block harmful/explicit content": "Quand désactivé, indique à l'API (et non au modèle)\nde ne pas bloquer le contenu nuisible/explicite",
- "History": "Historique",
- "Saves chat history\nMessages in previous chats won't show automatically, but they are there": "Sauvegarde l'historique des discussions\nLes messages des conversations précédentes ne s'affichent pas automatiquement, mais ils existent",
- "Key stored in:": "Clé stockée dans :",
- "To update this key, type": "Pour mettre à jour cette clé, tapez",
- "Updated API Key at": "Clé API mise à jour le",
- "Currently using": "Actuellement utilisé",
- "Select ChatGPT-compatible API provider": "Sélectionnez un fournisseur d'API compatible ChatGPT",
- "Official OpenAI API.\nPricing: Free for the first $5 or 3 months, whichever is less.": "API officielle d'OpenAI.\nTarification : Gratuit pour les premiers 5 $ ou 3 mois, selon le moindre des deux.",
- "Official Ollama API.\nPricing: Free.": "API officielle d'Ollama.\nTarification : Gratuit.",
- "A unified interface for LLMs": "Une interface unifiée pour les LLM",
- "An API from Tornado Softwares\nPricing: Free: 100/day\nRequires you to join their Discord for a key": "Une API de Tornado Softwares\nTarification : Gratuit : 100 par jour\nNécessite de rejoindre leur Discord pour obtenir une clé",
- "An API from @zukixa on GitHub.\nNote: Keys are IP-locked so it's buggy sometimes\nPricing: Free: 10/min, 800/day.\nRequires you to join their Discord for a key": "Une API de @zukixa sur GitHub.\nNote : Les clés sont verrouillées par IP, ce qui peut provoquer des bugs\nTarification : Gratuit : 10/min, 800/jour.\nNécessite de rejoindre leur Discord pour obtenir une clé",
- "Provider shown above": "Fournisseur indiqué ci-dessus",
- "The model's temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1": "La valeur de température du modèle.\n Précis = 0\n Équilibré = 0.5\n Créatif = 1",
- "An API key is required\nYou can grab one here, then enter it below": "Une clé API est requise\nVous pouvez en obtenir une ici, puis la saisir ci-dessous",
- "Tells the model:\n- It's a Linux sidebar assistant\n- Be brief and use bullet points": "Indique au modèle :\n- C'est un assistant de barre latérale pour Linux\n- Sois concis et utilise des puces",
- "Powered by waifu.im + other APIs": "Propulsé par waifu.im + d'autres API",
- "Type tags for a random pic.\nNSFW content will not be returned unless\nyou explicitly request such a tag.\n\nDisclaimer: Not affiliated with the providers\nnor responsible for any of their content.": "Tapez des tags pour une image aléatoire.\nLe contenu NSFW ne sera pas affiché à moins que\nvous ne demandiez explicitement un tel tag.\n\nAvertissement : Pas affilié aux fournisseurs\net pas responsable de leur contenu.",
- "Tags →": "Tags →",
- "Invalid command.": "Commande invalide.",
- "Anime booru": "Booru d'anime",
- "Powered by yande.re and konachan": "Propulsé par yande.re et konachan",
- "An image booru. May contain NSFW content.\nWatch your back.\n\nDisclaimer: Not affiliated with the provider\nnor responsible for any of its content.": "Un booru d'images. Peut contenir du contenu NSFW.\nFais attention.\n\nAvertissement : Pas affilié au fournisseur\net pas responsable de son contenu.",
- "Lewds": "Contenu osé",
- "Shows naughty stuff when enabled": "Affiche du contenu osé lorsqu'il est activé",
- "Saves images in folders by their tags": "Enregistre les images dans des dossiers selon leurs tags",
- "Message Gemini...": "Envoyer un message à Gemini...",
- "Enter Google AI API Key...": "Saisissez la clé API de Google AI...",
- "Message the model...": "Envoyer un message au modèle...",
- "Enter API Key...": "Saisissez la clé API...",
- "Enter tags": "Saisissez les tags",
- "Quick scripts": "Scripts rapides",
- "Change screen resolution": "Changer la résolution de l'écran",
- "Update packages": "Mettre à jour les paquets",
- "Trim system generations to 5": "Limiter les générations système à 5",
- "Trim home manager generations to 5": "Limiter les générations de home-manager à 5",
- "Remove orphan packages": "Supprimer les paquets orphelins",
- "Uninstall unused flatpak packages": "Désinstaller les paquets Flatpak inutilisés",
- "Inaccurate Color picker": "Inexact Sélecteur de couleur",
- "Result": "Résultat",
- "Type to search": "Tapez pour rechercher",
- "illogical-impulse": "illogical-impulse",
- "RAM Usage": "Utilisation de la RAM",
- "Swap Usage": "Utilisation du swap",
- "CPU Usage": "Utilisation du CPU",
- "Uptime:": "Temps de fonctionnement :",
- "Screen snip": "Capture d'écran",
- "Color picker": "Sélecteur de couleur",
- "Toggle on-screen keyboard": "Activer/désactiver le clavier virtuel",
- "Night Light": "Lumière nocturne",
- "Color inversion": "Inversion des couleurs",
- "Keep system awake": "Empêcher la mise en veille du système",
- "Cloudflare WARP": "Cloudflare WARP",
- "Session": "Session",
- "Bluetooth | Right-click to configure": "Bluetooth | Clic droit pour configurer",
- "Wifi | Right-click to configure": "Wifi | Clic droit pour configurer",
- "Right-click to configure": "Clic droit pour configurer",
- "Unknown": "Inconnu",
- "Reload Environment config": "Recharger la configuration de l'environnement",
- "Open Settings": "Ouvrir les paramètres",
- "Notifications": "Notifications",
- "Audio controls": "Contrôles audio",
- "Bluetooth": "Bluetooth",
- "Wifi networks": "Réseaux Wifi",
- "Quick config": "Configuration",
- "Silence": "Silence",
- "Clear": "Effacer",
- "No notifications": "Aucune notification",
- "notifications": "notifications",
- "Close": "Fermer",
- "Now": "Maintenant",
- "Yesterday": "Hier",
- "No audio source": "Aucune source audio",
- "Remove device": "Retirer l'appareil",
- "Connected": "Connecté",
- "Paired": "Appairé",
- "More": "Plus",
- "Selected": "Sélectionné",
- "Current network": "Réseau actuel",
- "Authentication": "Authentification",
- "Effects": "Effets",
- "Transparency": "Transparence",
- "[AGS]\nMake shell elements transparent\nBlur is also recommended if you enable this": "[AGS]\nRendre les éléments de l'interface transparents\nLe flou est également recommandé si vous l'activez.\nChoisissez un fond d'écran avant d'activer cette option.",
- "Blur": "Flou",
- "[Hyprland]\nEnable blur on transparent elements\nDoesn't affect performance/power consumption unless you have transparent windows.": "[Hyprland]\nActiver le flou sur les éléments transparents\nN'affecte pas les performances ou la consommation d'énergie, sauf en cas de fenêtres transparentes.",
- "X-ray": "Rayon X",
- "[Hyprland]\nMake everything behind a window/layer except the wallpaper not rendered on its blurred surface\nRecommended to improve performance (if you don't abuse transparency/blur) ": "[Hyprland]\nNe pas afficher ce qui se trouve derrière une fenêtre ou une couche (sauf le fond d'écran) sur sa surface floue\nRecommandé pour améliorer les performances (si vous n'abusez pas de la transparence/flou) ",
- "Size": "Taille",
- "[Hyprland]\nAdjust the blur radius. Generally doesn't affect performance\nHigher = more color spread": "[Hyprland]\nAjustez le rayon du flou. En général, cela n'affecte pas les performances\nPlus le rayon est grand, plus la diffusion des couleurs est importante",
- "Passes": "Passes",
- "[Hyprland] Adjust the number of runs of the blur algorithm\nMore passes = more spread and power consumption\n4 is recommended\n2- would look weird and 6+ would look lame.": "[Hyprland] Ajustez le nombre d'exécutions de l'algorithme de flou\nPlus il y a de passes, plus la diffusion et la consommation d'énergie augmentent\n4 est recommandé\n2 ou moins paraîtraient étranges et 6 ou plus sembleraient médiocres.",
- "Animations": "Animations",
- "[Hyprland] [GTK]\nEnable animations": "[Hyprland] [GTK]\nActiver les animations",
- "Choreography delay": "Délai de chorégraphie",
- "In milliseconds, the delay between animations of a series": "En millisecondes, le délai entre les animations d'une série",
- "Developer": "Développeur",
- "Show FPS": "Afficher les FPS",
- "[Hyprland]\nShow FPS overlay on top-left corner": "[Hyprland]\nAfficher une superposition FPS en haut à gauche",
- "Log to stdout": "Journaliser vers stdout",
- "[Hyprland]\nPrint LOG, ERR, WARN, etc. messages to the console": "[Hyprland]\nAfficher les messages LOG, ERR, WARN, etc. dans la console",
- "Damage tracking": "Suivi des dégâts",
- "[Hyprland]\nEnable damage tracking\nGenerally, leave it on.\nTurn off only when a shader doesn't work": "[Hyprland]\nActiver le suivi des dégâts\nEn général, laissez-le activé.\nDésactivez-le uniquement si un shader ne fonctionne pas",
- "Damage blink": "Clignotement des dégâts",
- "[Hyprland] [Epilepsy warning!]\nShow screen damage flashes": "[Hyprland] [Avertissement épilepsie !]\nAfficher des flashs lors des modifications de l'écran",
- "Not all changes are saved": "Tous les changements ne sont pas enregistrés",
- "Mo": "Lu",
- "Tu": "Ma",
- "We": "Me",
- "Th": "Je",
- "Fr": "Ve",
- "Sa": "Sa",
- "Su": "Di",
- "Calendar": "Calendrier",
- "To Do": "À faire",
- "Unfinished": "Non terminé",
- "Done": "Terminé",
- "Finished tasks will go here": "Les tâches terminées apparaîtront ici",
- "Nothing here!": "Rien ici !",
- "+ New task": "+ Nouvelle tâche",
- "Add a task...": "Ajouter une tâche...",
- "Color scheme": "Schéma de couleurs",
- "Options": "Options",
- "Dark Mode": "Mode sombre",
- "Ya should go to sleep!": "Tu devrais aller dormir !",
- "Theme GTK apps using accent color\n(drawback: dark/light mode switching requires restart)": "Thématiser les applications GTK avec la couleur d'accent\n(inconvénient : le changement de mode sombre/clair nécessite un redémarrage)",
- "Scheme styles": "Styles de schéma",
- "Vibrant": "Vibrant",
- "Vibrant+": "Vibrant+",
- "Expressive": "Expressif",
- "Monochrome": "Monochrome",
- "Rainbow": "Arc-en-ciel",
- "Fidelity": "Fidélité",
- "Fruit Salad": "Salade de fruits",
- "Tonal Spot": "Tonal Spot",
- "Content": "Contenu",
- "Use arrow keys to navigate.\nEnter to select, Esc to cancel.": "Utilise les flèches pour naviguer.\nEntrée pour sélectionner, Échap pour annuler.",
- "Lock": "Verrouiller",
- "Logout": "Se déconnecter",
- "Sleep": "Mettre en veille",
- "Hibernate": "Hibernation",
- "Shutdown": "Éteindre",
- "Reboot": "Redémarrer",
- "Cancel": "Annuler",
- "Cheat sheet": "Aide-mémoire",
- "Keybinds": "Raccourcis clavier",
- "Periodic table": "Tableau périodique",
- "Essentials for beginners": "Notions essentielles pour débutants",
- "Make shell elements transparent": "Rendre les éléments de l'interface transparents",
- "Actions": "Actions",
- "Window management": "Gestion des fenêtres",
- "Window arrangement": "Disposition des fenêtres",
- "Workspace management": "Gestion des espaces de travail",
- "Workspace navigation": "Navigation entre espaces de travail",
- "Widgets": "Widgets",
- "Media": "Médias",
- "Apps": "Applications",
- "Neutral": "Neutre",
- "Launch foot (terminal)": "Lancer foot (terminal)",
- "Open app launcher": "Ouvrir le lanceur d'applications",
- "Change wallpaper": "Changer le fond d'écran",
- "Clipboard history >> clipboard": "Historique du presse-papiers >> presse-papiers",
- "Pick emoji >> clipboard": "Choisir un emoji >> presse-papiers",
- "Screen snip >> edit": "Capture d'écran >> éditer",
- "Screen snip to text >> clipboard": "Capture d'écran en texte >> presse-papiers",
- "Pick color (Hex) >> clipboard": "Choisir une couleur (Hex) >> presse-papiers",
- "Screenshot >> clipboard": "Capture d'écran >> presse-papiers",
- "Screenshot >> clipboard & file": "Capture d'écran >> presse-papiers & fichier",
- "Record region (no sound)": "Enregistrer une région (sans son)",
- "Record screen (with sound)": "Enregistrer l'écran (avec son)",
- "Suspend system": "Suspendre le système",
- "Move focus in direction": "Déplacer le focus dans la direction",
- "Move window": "Déplacer la fenêtre",
- "Resize window": "Redimensionner la fenêtre",
- "Close window": "Fermer la fenêtre",
- "Pick and kill a window": "Sélectionner et fermer une fenêtre",
- "Window: move in direction": "Fenêtre : déplacer dans la direction",
- "Window: split ratio +/- 0.1": "Fenêtre : ajuster le ratio de partage +/- 0.1",
- "Float/unfloat window": "Basculer la fenêtre en mode flottant/non flottant",
- "Toggle fake fullscreen": "Basculer en faux plein écran",
- "Toggle fullscreen": "Basculer le plein écran",
- "Toggle maximization": "Basculer la maximisation",
- "Focus workspace # (1, 2, 3, 4, ...)": "Sélectionner l'espace de travail n° (1, 2, 3, 4, ...)",
- "Workspace: focus left/right": "Espace de travail : se déplacer à gauche/droite",
- "Workspace: toggle special": "Espace de travail : basculer spécial",
- "Window: move to workspace # (1, 2, 3, 4, ...)": "Fenêtre : déplacer vers l'espace de travail n° (1, 2, 3, 4, ...)",
- "Window: move to workspace left/right": "Fenêtre : déplacer vers l'espace de travail à gauche/droite",
- "Window: move to workspace special": "Fenêtre : déplacer vers l'espace de travail spécial",
- "Window: pin (show on all workspaces)": "Fenêtre : épingler (afficher sur tous les espaces de travail)",
- "Restart widgets": "Redémarrer les widgets",
- "Cycle bar mode (normal, focus)": "Cycler le mode de la barre (normal, focus)",
- "Toggle overview/launcher": "Basculer l'aperçu/le lanceur",
- "Show cheatsheet": "Afficher l'aide-mémoire",
- "Toggle left sidebar": "Basculer la barre latérale gauche",
- "Toggle right sidebar": "Basculer la barre latérale droite",
- "Toggle music controls": "Basculer les contrôles de musique",
- "View color scheme and options": "Voir le schéma de couleurs et les options",
- "Toggle power menu": "Basculer le menu d'alimentation",
- "Toggle crosshair": "Basculer le viseur",
- "Next track": "Piste suivante",
- "Previous track": "Piste précédente",
- "Play/pause media": "Lire/metre en pause le média",
- "Launch Zed (editor)": "Lancer Zed (éditeur)",
- "Launch VSCode (editor)": "Lancer VSCode (éditeur)",
- "Launch Nautilus (file manager)": "Lancer Nautilus (gestionnaire de fichiers)",
- "Launch Firefox (browser)": "Lancer Firefox (navigateur)",
- "Launch GNOME Text Editor": "Lancer GNOME Text Editor",
- "Launch WPS Office": "Lancer WPS Office",
- "Launch GNOME Settings": "Lancer les paramètres GNOME",
- "Launch pavucontrol (volume mixer)": "Lancer pavucontrol (contrôleur de volume)",
- "Launch EasyEffects (equalizer & other audio effects)": "Lancer EasyEffects (égaliseur et autres effets audio)",
- "Launch GNOME System monitor": "Lancer le moniteur système GNOME",
- "Toggle fallback launcher: anyrun": "Basculer le lanceur de secours : anyrun",
- "Toggle fallback launcher: fuzzel": "Basculer le lanceur de secours : fuzzel",
- "Initialization complete!": "Initialisation terminée !",
- "Not found": "Non trouvé :",
- "Calling API": "Appel de l'API",
- "Downloading image": "Téléchargement de l'image",
- "Finished!": "Terminé !",
- "Error": "Erreur",
- "Not found!": "Non trouvé !",
- "Go to file url": "Aller à l'URL du fichier",
- "Save image": "Enregistrer l'image",
- "Hoard": "Accumuler",
- "Open externally": "Ouvrir avec une application externe",
- "You are an assistant on a sidebar of a Wayland Linux desktop. Please always use a casual tone when answering your questions, unless requested otherwise or making writing suggestions. These are the steps you should take to respond to the user's queries:\n1. If it's a writing- or grammar-related question or a sentence in quotation marks, Please point out errors and correct when necessary using underlines, and make the writing more natural where appropriate without making too major changes. If you're given a sentence in quotes but is grammatically correct, explain briefly concepts that are uncommon.\n2. If it's a question about system tasks, give a bash command in a code block with brief explanation.\n3. Otherwise, when asked to summarize information or explaining concepts, you are should use bullet points and headings. For mathematics expressions, you *have to* use LaTeX within a code block with the language set as \"latex\". \nNote: Use casual language, be short, while ensuring the factual correctness of your response. If you are unsure or don’t have enough information to provide a confident answer, simply say “I don’t know” or “I'm not sure.”. \nThanks!": "Tu es un assistant dans un panneau latéral d'un bureau Linux sous Wayland. Veilles à toujours adopter un ton décontracté lorsque tu réponds, sauf indication contraire ou lors de suggestions d'écriture. Voici les étapes à suivre pour répondre aux requêtes de l'utilisateur :\n1. S'il s'agit d'une question liée à l'écriture ou à la grammaire, ou d'une phrase entre guillemets, signales les erreurs et corriges-les si nécessaire en utilisant des soulignements, et rends l'écriture plus naturelle lorsque cela est approprié sans apporter de modifications trop importantes. Si on te fournit une phrase entre guillemets mais grammaticalement correcte, expliques brièvement des concepts peu communs.\n2. S'il s'agit d'une question concernant des tâches système, fournis une commande bash dans un bloc de code avec une brève explication.\n3. Sinon, lorsqu'on te demande de résumer des informations ou d'expliquer des concepts, utilises des puces et des titres. Pour les expressions mathématiques, tu *dois* utiliser LaTeX dans un bloc de code avec la langue définie sur \"latex\".\nNote : Utilises un langage décontracté, sois bref, tout en garantissant l'exactitude des informations de ta réponse. Si tu n'es pas sûr ou si tu ne disposes pas d'assez d'informations pour fournir une réponse convaincante, dis simplement \"Je ne sais pas\" ou \"Je ne suis pas sûr\".\nMerci !",
- "Feels like": "Ressenti"
- }
-
\ No newline at end of file
diff --git a/.config/ags/i18n/locales/it_IT.json b/.config/ags/i18n/locales/it_IT.json
deleted file mode 100644
index b572d1b92..000000000
--- a/.config/ags/i18n/locales/it_IT.json
+++ /dev/null
@@ -1,238 +0,0 @@
-{
- "No media": "Nessun media",
- "Powered by Google": "Offerto da Google",
- "Not affiliated, endorsed, or sponsored by Google.\n\nPrivacy: Chat messages aren't linked to your account,\nbut will be read by human reviewers to improve the model.": "Non affiliato, approvato o sponsorizzato da Google.\n\nPrivacy: I messaggi della chat non sono collegati al tuo account,\n ma saranno letti da revisori umani per migliorare il modello.",
- "Precise": "Preciso",
- "Balanced": "Bilanciato",
- "Creative": "Creativo",
- "Gemini's temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1": "Valore di temperatura di Gemini.\n Preciso = 0\n Bilanciato = 0.5\n Creativo = 1",
- "Enhancements": "Miglioramenti",
- "Tells Gemini:\n- It's a Linux sidebar assistant\n- Be brief and use bullet points": "Dice a Gemini:\n- È un assistente laterale per Linux\n- Sii breve e usa punti elenco",
- "Safety": "Sicurezza",
- "When turned off, tells the API (not the model) \nto not block harmful/explicit content": "Quando disattivato, dice all'API (non al modello) \n di non bloccare contenuti dannosi/espliciti",
- "History": "Cronologia",
- "Saves chat history\nMessages in previous chats won't show automatically, but they are there": "Salva la cronologia della chat\nI messaggi nelle chat precedenti non verranno mostrati automaticamente, ma sono lì",
- "Key stored in:": "Chiave memorizzata in:",
- "To update this key, type": "Per aggiornare questa chiave, digita",
- "Updated API Key at": "Chiave API aggiornata alle",
- "Currently using": "Attualmente in uso",
- "Select ChatGPT-compatible API provider": "Seleziona un provider API compatibile con ChatGPT",
- "Official OpenAI API.\nPricing: Free for the first $5 or 3 months, whichever is less.": "API ufficiale di OpenAI.\nPrezzi: Gratuito per i primi $5 o 3 mesi, a seconda di quale sia inferiore.",
- "Official Ollama API.\nPricing: Free.": "API ufficiale di Ollama.\nPrezzi: Gratuito.",
- "A unified interface for LLMs": "Un'interfaccia unificata per LLM",
- "An API from Tornado Softwares\nPricing: Free: 100/day\nRequires you to join their Discord for a key": "Un'API di Tornado Softwares\nPrezzi: Gratuito: 100/giorno\nRichiede di unirsi al loro Discord per una chiave",
- "An API from @zukixa on GitHub.\nNote: Keys are IP-locked so it's buggy sometimes\nPricing: Free: 10/min, 800/day.\nRequires you to join their Discord for a key": "Un'API di @zukixa su GitHub.\nNota: Le chiavi sono bloccate per IP, quindi a volte è instabile\nPrezzi: Gratuito: 10/min, 800/giorno.\nRichiede di unirsi al loro Discord per una chiave",
- "Provider shown above": "Provider mostrato sopra",
- "The model's temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1": "Valore di temperatura del modello.\n Preciso = 0\n Bilanciato = 0.5\n Creativo = 1",
- "An API key is required\nYou can grab one here, then enter it below": "È necessaria una chiave API\nPuoi ottenerne una qui, quindi inserirla qui sotto",
- "Tells the model:\n- It's a Linux sidebar assistant\n- Be brief and use bullet points": "Dice al modello:\n- È un assistente laterale per Linux\n- Sii breve e usa punti elenco",
- "Powered by waifu.im + other APIs": "Offerto da waifu.im + altre API",
- "Type tags for a random pic.\nNSFW content will not be returned unless\nyou explicitly request such a tag.\n\nDisclaimer: Not affiliated with the providers\nnor responsible for any of their content.": "Digita i tag per un'immagine casuale.\nIl contenuto NSFW non verrà restituito a meno che\nnon richiedi esplicitamente un tale tag.\n\nDisclaimer: Non affiliato ai provider\nné responsabile per alcun loro contenuto.",
- "Tags →": "Tag →",
- "Invalid command.": "Comando non valido.",
- "Anime booru": "Anime booru",
- "Powered by yande.re and konachan": "Offerto da yande.re e konachan",
- "An image booru. May contain NSFW content.\nWatch your back.\n\nDisclaimer: Not affiliated with the provider\nnor responsible for any of its content.": "Un booru di immagini. Potrebbe contenere contenuti NSFW.\nFai attenzione.\n\nDisclaimer: Non affiliato al provider\nné responsabile per alcun suo contenuto.",
- "Lewds": "Contenuti osé",
- "Shows naughty stuff when enabled": "Mostra contenuti osé quando abilitato",
- "Saves images in folders by their tags": "Salva le immagini in cartelle in base ai loro tag",
- "Message Gemini...": "Messaggia Gemini...",
- "Enter Google AI API Key...": "Inserisci la chiave API di Google AI...",
- "Message the model...": "Messaggia il modello...",
- "Enter API Key...": "Inserisci la chiave API...",
- "Enter tags": "Inserisci i tag",
- "Quick scripts": "Script rapidi",
- "Change screen resolution": "Cambia risoluzione dello schermo",
- "Update packages": "Aggiorna i pacchetti",
- "Trim system generations to 5": "Riduci le generazioni del sistema a 5",
- "Trim home manager generations to 5": "Riduci le generazioni del gestore di casa a 5",
- "Remove orphan packages": "Rimuovi i pacchetti orfani",
- "Uninstall unused flatpak packages": "Disinstalla i pacchetti flatpak non utilizzati",
- "Inaccurate Color picker": "Impreciso Selettore di colore",
- "Result": "Risultato",
- "Type to search": "Digita per cercare",
- "illogical-impulse": "impulso illogico",
- "RAM Usage": "Utilizzo della RAM",
- "Swap Usage": "Utilizzo dello Swap",
- "CPU Usage": "Utilizzo della CPU",
- "Uptime:": "Tempo di attività:",
- "Screen snip": "Ritaglio dello schermo",
- "Color picker": "Selettore di colore",
- "Toggle on-screen keyboard": "Attiva/disattiva tastiera su schermo",
- "Night Light": "Luce notturna",
- "Color inversion": "Inversione di colore",
- "Keep system awake": "Mantieni il sistema sveglio",
- "Cloudflare WARP": "Cloudflare WARP",
- "Session": "Sessione",
- "Bluetooth | Right-click to configure": "Bluetooth | Clic destro per configurare",
- "Wifi | Right-click to configure": "Wifi | Clic destro per configurare",
- "Right-click to configure": "Clic destro per configurare",
- "Unknown": "Sconosciuto",
- "Reload Environment config": "Ricarica la configurazione dell'ambiente",
- "Open Settings": "Apri Impostazioni",
- "Notifications": "Notifiche",
- "Audio controls": "Controlli audio",
- "Bluetooth": "Bluetooth",
- "Wifi networks": "Reti Wifi",
- "Quick config": "Configurazione",
- "Silence": "Silenzio",
- "Clear": "Cancella",
- "No notifications": "Nessuna notifica",
- "notifications": "notifiche",
- "Close": "Chiudi",
- "Now": "Ora",
- "Yesterday": "Ieri",
- "No audio source": "Nessuna sorgente audio",
- "Remove device": "Rimuovi dispositivo",
- "Connected": "Connesso",
- "Paired": "Abbinato",
- "More": "Altro",
- "Selected": "Selezionato",
- "Current network": "Rete corrente",
- "Authentication": "Autenticazione",
- "Effects": "Effetti",
- "Transparency": "Trasparenza",
- "[AGS]\nMake shell elements transparent\nBlur is also recommended if you enable this": "[AGS]\nRendi trasparenti gli elementi della shell\nSi consiglia anche il blur se abiliti questa opzione",
- "Blur": "Blur",
- "[Hyprland]\nEnable blur on transparent elements\nDoesn't affect performance/power consumption unless you have transparent windows.": "[Hyprland]\nAbilita il blur sugli elementi trasparenti\nNon influisce sulle prestazioni/consumo energetico a meno che non si abbiano finestre trasparenti.",
- "X-ray": "Raggi X",
- "[Hyprland]\nMake everything behind a window/layer except the wallpaper not rendered on its blurred surface\nRecommended to improve performance (if you don't abuse transparency/blur) ": "[Hyprland]\nRendi tutto dietro una finestra/livello, tranne lo sfondo, non renderizzato sulla sua superficie sfocata\nConsigliato per migliorare le prestazioni (se non abusi di trasparenza/blur) ",
- "Size": "Dimensione",
- "[Hyprland]\nAdjust the blur radius. Generally doesn't affect performance\nHigher = more color spread": "[Hyprland]\nRegola il raggio del blur. Generalmente non influisce sulle prestazioni\nPiù alto = più diffusione del colore",
- "Passes": "Passaggi",
- "[Hyprland] Adjust the number of runs of the blur algorithm\nMore passes = more spread and power consumption\n4 is recommended\n2- would look weird and 6+ would look lame.": "[Hyprland] Regola il numero di esecuzioni dell'algoritmo di blur\nPiù passaggi = più diffusione e consumo energetico\nSi consigliano 4\n2- sembrerebbe strano e 6+ sembrerebbe scadente.",
- "Animations": "Animazioni",
- "[Hyprland] [GTK]\nEnable animations": "[Hyprland] [GTK]\nAbilita le animazioni",
- "Choreography delay": "Ritardo della coreografia",
- "In milliseconds, the delay between animations of a series": "In millisecondi, il ritardo tra le animazioni di una serie",
- "Developer": "Sviluppatore",
- "Show FPS": "Mostra FPS",
- "[Hyprland]\nShow FPS overlay on top-left corner": "[Hyprland]\nMostra l'overlay degli FPS nell'angolo in alto a sinistra",
- "Log to stdout": "Log su stdout",
- "[Hyprland]\nPrint LOG, ERR, WARN, etc. messages to the console": "[Hyprland]\nStampa i messaggi LOG, ERR, WARN, ecc. sulla console",
- "Damage tracking": "Tracciamento dei danni",
- "[Hyprland]\nEnable damage tracking\nGenerally, leave it on.\nTurn off only when a shader doesn't work": "[Hyprland]\nAbilita il tracciamento dei danni\nGeneralmente, lascialo acceso.\nDisattivalo solo quando uno shader non funziona",
- "Damage blink": "Lampeggio dei danni",
- "[Hyprland] [Epilepsy warning!]\nShow screen damage flashes": "[Hyprland] [Avviso epilessia!]\nMostra i lampeggi dei danni dello schermo",
- "Not all changes are saved": "Non tutte le modifiche sono state salvate",
- "Mo": "Lu",
- "Tu": "Ma",
- "We": "Me",
- "Th": "Gi",
- "Fr": "Ve",
- "Sa": "Sa",
- "Su": "Do",
- "Calendar": "Calendario",
- "To Do": "Da fare",
- "Unfinished": "Incompleto",
- "Done": "Fatto",
- "Finished tasks will go here": "Le attività completate andranno qui",
- "Nothing here!": "Niente qui!",
- "+ New task": "+ Nuova attività",
- "Add a task...": "Aggiungi un'attività...",
- "Color scheme": "Schema di colori",
- "Options": "Opzioni",
- "Dark Mode": "Modalità scura",
- "Ya should go to sleep!": "Dovresti andare a dormire!",
- "Theme GTK apps using accent color\n(drawback: dark/light mode switching requires restart)": "Tema le app GTK usando il colore di accento\n(svantaggio: il passaggio tra modalità scura/chiara richiede un riavvio)",
- "Scheme styles": "Stili dello schema",
- "Vibrant": "Vivace",
- "Vibrant+": "Vivace+",
- "Expressive": "Espressivo",
- "Monochrome": "Monocromatico",
- "Rainbow": "Arcobaleno",
- "Fidelity": "Fedeltà",
- "Fruit Salad": "Macedonia di frutta",
- "Tonal Spot": "Punto tonale",
- "Content": "Contenuto",
- "Use arrow keys to navigate.\nEnter to select, Esc to cancel.": "Usa i tasti freccia per navigare.\nInvio per selezionare, Esc per annullare.",
- "Lock": "Blocca",
- "Logout": "Esci",
- "Sleep": "Sospendi",
- "Hibernate": "Iberna",
- "Shutdown": "Spegni",
- "Reboot": "Riavvia",
- "Cancel": "Annulla",
- "Cheat sheet": "Foglio di riferimento",
- "Keybinds": "Scorciatoie da tastiera",
- "Periodic table": "Tavola periodica",
- "Essentials for beginners": "Essenziali per principianti",
- "Make shell elements transparent": "Rendi trasparenti gli elementi della shell",
- "Actions": "Azioni",
- "Window management": "Gestione delle finestre",
- "Window arrangement": "Disposizione delle finestre",
- "Workspace management": "Gestione degli spazi di lavoro",
- "Workspace navigation": "Navigazione degli spazi di lavoro",
- "Widgets": "Widget",
- "Media": "Media",
- "Apps": "App",
- "Neutral": "Neutro",
- "Launch foot (terminal)": "Avvia foot (terminale)",
- "Open app launcher": "Apri il launcher delle app",
- "Change wallpaper": "Cambia lo sfondo",
- "Clipboard history >> clipboard": "Cronologia degli appunti >> appunti",
- "Pick emoji >> clipboard": "Scegli emoji >> appunti",
- "Screen snip >> edit": "Ritaglio dello schermo >> modifica",
- "Screen snip to text >> clipboard": "Ritaglio dello schermo in testo >> appunti",
- "Pick color (Hex) >> clipboard": "Scegli colore (Hex) >> appunti",
- "Screenshot >> clipboard": "Screenshot >> appunti",
- "Screenshot >> clipboard & file": "Screenshot >> appunti e file",
- "Record region (no sound)": "Registra regione (senza audio)",
- "Record screen (with sound)": "Registra schermo (con audio)",
- "Suspend system": "Sospendi il sistema",
- "Move focus in direction": "Sposta il focus nella direzione",
- "Move window": "Sposta la finestra",
- "Resize window": "Ridimensiona la finestra",
- "Close window": "Chiudi la finestra",
- "Pick and kill a window": "Scegli e chiudi una finestra",
- "Window: move in direction": "Finestra: sposta nella direzione",
- "Window: split ratio +/- 0.1": "Finestra: rapporto di divisione +/- 0.1",
- "Float/unfloat window": "Finestra libera/agganciata",
- "Toggle fake fullscreen": "Attiva/disattiva falso fullscreen",
- "Toggle fullscreen": "Attiva/disattiva fullscreen",
- "Toggle maximization": "Attiva/disattiva massimizzazione",
- "Focus workspace # (1, 2, 3, 4, ...)": "Focalizza spazio di lavoro # (1, 2, 3, 4, ...)",
- "Workspace: focus left/right": "Spazio di lavoro: focalizza sinistra/destra",
- "Workspace: toggle special": "Spazio di lavoro: attiva/disattiva speciale",
- "Window: move to workspace # (1, 2, 3, 4, ...)": "Finestra: sposta in spazio di lavoro # (1, 2, 3, 4, ...)",
- "Window: move to workspace left/right": "Finestra: sposta in spazio di lavoro sinistra/destra",
- "Window: move to workspace special": "Finestra: sposta in spazio di lavoro speciale",
- "Window: pin (show on all workspaces)": "Finestra: fissa (mostra su tutti gli spazi di lavoro)",
- "Restart widgets": "Riavvia widget",
- "Cycle bar mode (normal, focus)": "Cicla modalità barra (normale, focus)",
- "Toggle overview/launcher": "Attiva/disattiva panoramica/lanciatore",
- "Show cheatsheet": "Mostra cheatsheet",
- "Toggle left sidebar": "Attiva/disattiva barra laterale sinistra",
- "Toggle right sidebar": "Attiva/disattiva barra laterale destra",
- "Toggle music controls": "Attiva/disattiva controlli musicali",
- "View color scheme and options": "Visualizza schema colori e opzioni",
- "Toggle power menu": "Attiva/disattiva menu di spegnimento",
- "Toggle crosshair": "Attiva/disattiva mirino",
- "Next track": "Traccia successiva",
- "Previous track": "Traccia precedente",
- "Play/pause media": "Riproduci/pausa media",
- "Launch Zed (editor)": "Avvia Zed (editor)",
- "Launch VSCode (editor)": "Avvia VSCode (editor)",
- "Launch Nautilus (file manager)": "Avvia Nautilus (gestore file)",
- "Launch Firefox (browser)": "Avvia Firefox (browser)",
- "Launch GNOME Text Editor": "Avvia GNOME Text Editor",
- "Launch WPS Office": "Avvia WPS Office",
- "Launch GNOME Settings": "Avvia Impostazioni GNOME",
- "Launch pavucontrol (volume mixer)": "Avvia pavucontrol (mixer volume)",
- "Launch EasyEffects (equalizer & other audio effects)": "Avvia EasyEffects (equalizzatore & altri effetti audio)",
- "Launch GNOME System monitor": "Avvia monitor di sistema GNOME",
- "Toggle fallback launcher: anyrun": "Attiva/disattiva lanciatore di riserva: anyrun",
- "Toggle fallback launcher: fuzzel": "Attiva/disattiva lanciatore di riserva: fuzzel",
- "Initialization complete!": "Inizializzazione completata!",
- "Not found": "Non trovato",
- "Calling API": "Chiamata API",
- "Downloading image": "Scaricamento immagine",
- "Finished!": "Completato!",
- "Error": "Errore",
- "Not found!": "Non trovato!",
- "Go to file url": "Vai all'url del file",
- "Save image": "Salva immagine",
- "Hoard": "Accumula",
- "Open externally": "Apri esternamente",
- "You are an assistant on a sidebar of a Wayland Linux desktop. Please always use a casual tone when answering your questions, unless requested otherwise or making writing suggestions. These are the steps you should take to respond to the user's queries:\n1. If it's a writing- or grammar-related question or a sentence in quotation marks, Please point out errors and correct when necessary using underlines, and make the writing more natural where appropriate without making too major changes. If you're given a sentence in quotes but is grammatically correct, explain briefly concepts that are uncommon.\n2. If it's a question about system tasks, give a bash command in a code block with brief explanation.\n3. Otherwise, when asked to summarize information or explaining concepts, you are should use bullet points and headings. For mathematics expressions, you *have to* use LaTeX within a code block with the language set as \"latex\". \nNote: Use casual language, be short, while ensuring the factual correctness of your response. If you are unsure or don’t have enough information to provide a confident answer, simply say “I don’t know” or “I’m not sure.”. \nThanks!": "Sei un assistente nella barra laterale di un desktop Wayland Linux. Usa sempre un tono informale quando rispondi alle domande, a meno che non venga richiesto diversamente o quando fai suggerimenti di scrittura. Ecco i passaggi che devi seguire per rispondere alle domande dell'utente:\n1. Se si tratta di una domanda sulla scrittura o sulla grammatica o di una frase tra virgolette, segnala gli errori e correggi quando necessario utilizzando sottolineature, e rendi la scrittura più naturale dove appropriato senza fare modifiche troppo importanti. Se ti viene data una frase tra virgolette ma è grammaticalmente corretta, spiega brevemente concetti che sono poco comuni.\n2. Se è una domanda su attività di sistema, fornisci un comando bash in un blocco di codice con una breve spiegazione.\n3. Altrimenti, quando ti viene chiesto di riassumere informazioni o spiegare concetti, usa punti elenco e titoli. Per espressioni matematiche, *devi* usare LaTeX all'interno di un blocco di codice con il linguaggio impostato su \"latex\". \nNota: usa un linguaggio informale, sii breve, assicurandoti della correttezza fattuale della tua risposta. Se non sei sicuro o non hai abbastanza informazioni per fornire una risposta sicura, semplicemente dici “Non lo so” o “Non sono sicuro”. \nGrazie!"
-}
\ No newline at end of file
diff --git a/.config/ags/i18n/locales/zh_CN.json b/.config/ags/i18n/locales/zh_CN.json
deleted file mode 100644
index 906090be5..000000000
--- a/.config/ags/i18n/locales/zh_CN.json
+++ /dev/null
@@ -1,239 +0,0 @@
-{
- "No media": "无媒体活动",
- "Powered by Google": "由 Google 提供技术支持",
- "Not affiliated, endorsed, or sponsored by Google.\n\nPrivacy: Chat messages aren't linked to your account,\nbut will be read by human reviewers to improve the model.": "不隶属于、不受 Google 赞助或支持。\n\n隐私:聊天信息不会与你的账户关联,\n但会被人类审阅者阅读,用于改进模型。",
- "Precise": "精确",
- "Balanced": "平衡",
- "Creative": "创意",
- "Gemini's temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1": "Gemini 的 temperature 值\n 精确 = 0\n 平衡 = 0.5\n 创意 = 1",
- "Enhancements": "增强功能",
- "Tells Gemini:\n- It's a Linux sidebar assistant\n- Be brief and use bullet points": "告诉 Gemini:\n- 它是一个 Linux 侧边栏助手\n- 保持简洁并使用项目符号",
- "Safety": "安全",
- "When turned off, tells the API (not the model) \nto not block harmful/explicit content": "当关闭时,告诉 API(而不是模型)\n不要屏蔽有害/显露的内容",
- "History": "历史",
- "Saves chat history\nMessages in previous chats won't show automatically, but they are there": "保存聊天历史\n以前聊天中的消息不会自动显示,但它们仍然存在",
- "Key stored in:": "密钥值储存在:",
- "To update this key, type": "要更新此密钥,请输入",
- "Updated API Key at": "更新了 API 密钥于",
- "Currently using": "当前使用",
- "Select ChatGPT-compatible API provider": "选择与 ChatGPT 兼容的 API 提供商",
- "Official OpenAI API.\nPricing: Free for the first $5 or 3 months, whichever is less.": "官方 OpenAI API。\n定价:前 $5 或前 3 个月免费,取较小者。",
- "Official Ollama API.\nPricing: Free.": "官方 Ollama API。\n定价:免费。",
- "A unified interface for LLMs": "LLM 的统一接口",
- "An API from Tornado Softwares\nPricing: Free: 100/day\nRequires you to join their Discord for a key": "来自 Tornado Softwares 的 API\n定价:免费:每天 100 次请求\n需要加入他们的 Discord 以获取密钥",
- "An API from @zukixa on GitHub.\nNote: Keys are IP-locked so it's buggy sometimes\nPricing: Free: 10/min, 800/day.\nRequires you to join their Discord for a key": "来自 GitHub 上的 @zukixa 的 API。\n注意:密钥与 IP 绑定,所以有时会出错。\n定价:免费:每分钟 10 次,每天 800 次。\n需要加入他们的 Discord 才能获得密钥。",
- "Provider shown above": "上述显示的提供商",
- "The model's temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1": "模型的 temperature 值。\n 精确 = 0\n 平衡 = 0.5\n 创意 = 1",
- "An API key is required\nYou can grab one here, then enter it below": "需要 API 密钥\n您可以在这里获取一个,然后在下面输入",
- "Tells the model:\n- It's a Linux sidebar assistant\n- Be brief and use bullet points": "告诉模型:\n- 它是一个 Linux 侧边栏助手\n- 保持简洁并使用项目符号",
- "Powered by waifu.im + other APIs": "由 waifu.im + 其他 API 提供支持",
- "Type tags for a random pic.\nNSFW content will not be returned unless\nyou explicitly request such a tag.\n\nDisclaimer: Not affiliated with the providers\nnor responsible for any of their content.": "输入标签以获取随机图片。\n除非您明确请求,否则不会返回 NSFW 内容。\n\n免责声明:与提供商无关联\n我也不对他们的任何内容负责。",
- "Tags →": "标签 →",
- "Invalid command.": "无效命令。",
- "Anime booru": "动漫图库",
- "Powered by yande.re and konachan": "由 yande.re 和 konachan 提供支持",
- "An image booru. May contain NSFW content.\nWatch your back.\n\nDisclaimer: Not affiliated with the provider\nnor responsible for any of its content.": "一个图片图库。可能包含 NSFW 内容。\n小心。\n\n免责声明:与提供商无关联\n也不对它的任何内容负责。",
- "Lewds": "不雅内容",
- "Shows naughty stuff when enabled": "启用时显示不雅内容",
- "Saves images in folders by their tags": "按标签将图片保存到文件夹中",
- "Message Gemini...": "向 Gemini 发送消息...",
- "Enter Google AI API Key...": "输入 Google AI API 密钥...",
- "Message the model...": "向模型发送消息...",
- "Enter API Key...": "输入 API 密钥...",
- "Enter tags": "输入标签",
- "Quick scripts": "快速脚本",
- "Change screen resolution": "更改屏幕分辨率",
- "Update packages": "更新软件包",
- "Trim system generations to 5": "将系统代数修剪为 5",
- "Trim home manager generations to 5": "将 home manager 代数修剪为 5",
- "Remove orphan packages": "移除孤立软件包",
- "Uninstall unused flatpak packages": "卸载未使用的 Flatpak 软件包",
- "Inaccurate Color picker": "不准确 颜色选择器",
- "Result": "结果",
- "Type to search": "输入以搜索",
- "illogical-impulse": "illogical-impulse",
- "RAM Usage": "RAM 使用情况",
- "Swap Usage": "Swap 使用情况",
- "CPU Usage": "CPU 使用情况",
- "Uptime:": "运行时间:",
- "Screen snip": "屏幕截图",
- "Color picker": "颜色选择器",
- "Toggle on-screen keyboard": "切换屏幕键盘",
- "Night Light": "夜灯",
- "Color inversion": "颜色反转",
- "Keep system awake": "保持系统唤醒",
- "Cloudflare WARP": "Cloudflare WARP",
- "Session": "会话",
- "Bluetooth | Right-click to configure": "蓝牙 | 右键单击以配置",
- "Wifi | Right-click to configure": "Wi-Fi | 右键单击以配置",
- "Right-click to configure": "右键单击以配置",
- "Unknown": "未知",
- "Reload Environment config": "重新加载环境配置",
- "Open Settings": "打开设置",
- "Notifications": "通知",
- "Audio controls": "音频控制",
- "Bluetooth": "蓝牙",
- "Wifi networks": "Wi-Fi 网络",
- "Quick config": "实时配置",
- "Silence": "静音",
- "Clear": "清除",
- "No notifications": "无通知",
- "notifications": "条通知",
- "Close": "关闭",
- "Now": "现在",
- "Yesterday": "昨天",
- "No audio source": "没有音频源",
- "Remove device": "移除设备",
- "Connected": "已连接",
- "Paired": "已配对",
- "More": "更多",
- "Selected": "已选中",
- "Current network": "当前网络",
- "Authentication": "身份验证",
- "Effects": "效果",
- "Transparency": "透明度",
- "[AGS]\nMake shell elements transparent\nBlur is also recommended if you enable this": "[AGS]\n使外壳元素透明\n如果启用此功能,也建议使用模糊效果",
- "Blur": "模糊",
- "[Hyprland]\nEnable blur on transparent elements\nDoesn't affect performance/power consumption unless you have transparent windows.": "[Hyprland]\n在透明元素上启用模糊效果\n除非您有透明窗口,否则不会影响性能/功耗。",
- "X-ray": "X-ray",
- "[Hyprland]\nMake everything behind a window/layer except the wallpaper not rendered on its blurred surface\nRecommended to improve performance (if you don't abuse transparency/blur) ": "[Hyprland]\n使窗口/图层后面的所有内容(除了壁纸)在其模糊表面上不渲染\n建议提高性能(如果您不滥用透明度/模糊)",
- "Size": "大小",
- "[Hyprland]\nAdjust the blur radius. Generally doesn't affect performance\nHigher = more color spread": "[Hyprland]\n调整模糊半径。通常不会影响性能\n数值越高 = 颜色扩散越大",
- "Passes": "次数",
- "[Hyprland] Adjust the number of runs of the blur algorithm\nMore passes = more spread and power consumption\n4 is recommended\n2- would look weird and 6+ would look lame.": "[Hyprland]\n调整模糊算法的运行次数\n次数越多 = 扩散越大,功耗越高\n建议使用 4 次\n2 次看起来很奇怪,6 次以上看起来很糟糕。",
- "Animations": "动画",
- "[Hyprland] [GTK]\nEnable animations": "[Hyprland] [GTK]\n启用动画",
- "Choreography delay": "间隔",
- "In milliseconds, the delay between animations of a series": "以毫秒为单位,一系列动画之间的延迟",
- "Developer": "开发者选项",
- "Show FPS": "显示 FPS",
- "[Hyprland]\nShow FPS overlay on top-left corner": "[Hyprland]\n在左上角显示 FPS 叠加层",
- "Log to stdout": "输出日志",
- "[Hyprland]\nPrint LOG, ERR, WARN, etc. messages to the console": "[Hyprland]\n将 LOG、ERR、WARN 等消息打印到控制台",
- "Damage tracking": "Damage tracking",
- "[Hyprland]\nEnable damage tracking\nGenerally, leave it on.\nTurn off only when a shader doesn't work": "[Hyprland]\n启用 Damage tracking \n通常情况下,保持启用状态\n仅当着色器无法正常工作时才禁用",
- "Damage blink": "显示视图更新",
- "[Hyprland] [Epilepsy warning!]\nShow screen damage flashes": "[Hyprland] [癫痫警告!]\n屏幕视图更新时闪烁",
- "Not all changes are saved": "并非所有更改都已保存",
- "Mo": "一",
- "Tu": "二",
- "We": "三",
- "Th": "四",
- "Fr": "五",
- "Sa": "六",
- "Su": "日",
- "Calendar": "日历",
- "To Do": "待办",
- "Unfinished": "未完成",
- "Done": "已完成",
- "Finished tasks will go here": "已完成的任务将显示在此处",
- "Nothing here!": "这里什么也没有!",
- "+ New task": "+ 新任务",
- "Add a task...": "添加任务...",
- "Color scheme": "配色方案",
- "Options": "选项",
- "Dark Mode": "深色模式",
- "Ya should go to sleep!": "你应该去睡觉!",
- "Theme GTK apps using accent color\n(drawback: dark/light mode switching requires restart)": "使用强调色对 GTK 应用程序进行主题化\n(缺点:深色/浅色模式切换需要重启)",
- "Scheme styles": "样式方案",
- "Vibrant": "鲜艳",
- "Vibrant+": "鲜艳+",
- "Expressive": "表现力",
- "Monochrome": "黑白",
- "Rainbow": "彩虹",
- "Fidelity": "保真度",
- "Fruit Salad": "水果沙拉",
- "Tonal Spot": "色调点",
- "Content": "内容",
- "Use arrow keys to navigate.\nEnter to select, Esc to cancel.": "使用箭头键导航。\n回车键选择,Esc 键取消。",
- "Lock": "锁屏",
- "Logout": "注销",
- "Sleep": "睡眠",
- "Hibernate": "休眠",
- "Shutdown": "关机",
- "Reboot": "重启",
- "Cancel": "取消",
- "Cheat sheet": "备忘单",
- "Keybinds": "按键绑定",
- "Periodic table": "元素周期表",
- "Essentials for beginners": "初学者必备",
- "Make shell elements transparent": "使外壳元素透明",
- "Actions": "操作",
- "Window management": "窗口管理",
- "Window arrangement": "窗口排列",
- "Workspace management": "工作区管理",
- "Workspace navigation": "工作区导航",
- "Widgets": "小部件",
- "Media": "媒体",
- "Apps": "应用程序",
- "Neutral": "中性",
- "Launch foot (terminal)": "启动终端(foot)",
- "Open app launcher": "打开应用程序启动器",
- "Change wallpaper": "更改壁纸",
- "Clipboard history >> clipboard": "剪贴板历史 >> 剪贴板",
- "Pick emoji >> clipboard": "选择表情符号 >> 剪贴板",
- "Screen snip >> edit": "屏幕截图 >> 编辑",
- "Screen snip to text >> clipboard": "屏幕截图转文字 >> 剪贴板",
- "Pick color (Hex) >> clipboard": "选择颜色(十六进制)>> 剪贴板",
- "Screenshot >> clipboard": "屏幕截图 >> 剪贴板",
- "Screenshot >> clipboard & file": "屏幕截图 >> 剪贴板和文件",
- "Record region (no sound)": "录制区域(无声音)",
- "Record screen (with sound)": "录制屏幕(带声音)",
- "Suspend system": "挂起系统",
- "Move focus in direction": "在方向上移动焦点",
- "Move window": "移动窗口",
- "Resize window": "调整窗口大小",
- "Close window": "关闭窗口",
- "Pick and kill a window": "选择并关闭一个窗口",
- "Window: move in direction": "窗口:在方向上移动",
- "Window: split ratio +/- 0.1": "窗口:分割比例 +/- 0.1",
- "Float/unfloat window": "浮动/取消浮动窗口",
- "Toggle fake fullscreen": "切换伪全屏",
- "Toggle fullscreen": "切换全屏",
- "Toggle maximization": "切换最大化",
- "Focus workspace # (1, 2, 3, 4, ...)": "聚焦工作区 #(1, 2, 3, 4, ...)",
- "Workspace: focus left/right": "工作区:聚焦左右",
- "Workspace: toggle special": "工作区:切换特殊工作区",
- "Window: move to workspace # (1, 2, 3, 4, ...)": "窗口:移动到工作区 #(1, 2, 3, 4, ...)",
- "Window: move to workspace left/right": "窗口:移动到左右工作区",
- "Window: move to workspace special": "窗口:移动到特殊工作区",
- "Window: pin (show on all workspaces)": "窗口:固定(在所有工作区显示)",
- "Restart widgets": "重启小部件",
- "Cycle bar mode (normal, focus)": "循环栏模式(正常,聚焦)",
- "Toggle overview/launcher": "切换概览/启动器",
- "Show cheatsheet": "显示快捷键表",
- "Toggle left sidebar": "切换左侧边栏",
- "Toggle right sidebar": "切换右侧边栏",
- "Toggle music controls": "切换音乐控制",
- "View color scheme and options": "查看配色方案和选项",
- "Toggle power menu": "切换电源菜单",
- "Toggle crosshair": "切换准星",
- "Next track": "下一曲目",
- "Previous track": "上一曲目",
- "Play/pause media": "播放/暂停媒体",
- "Launch Zed (editor)": "启动 Zed(编辑器)",
- "Launch VSCode (editor)": "启动 VSCode(编辑器)",
- "Launch Nautilus (file manager)": "启动 Nautilus(文件管理器)",
- "Launch Firefox (browser)": "启动 Firefox(浏览器)",
- "Launch GNOME Text Editor": "启动 GNOME 文本编辑器",
- "Launch WPS Office": "启动 WPS 办公软件",
- "Launch GNOME Settings": "启动 GNOME 设置",
- "Launch pavucontrol (volume mixer)": "启动 pavucontrol(音量混合器)",
- "Launch EasyEffects (equalizer & other audio effects)": "启动 EasyEffects(均衡器和其他音频效果)",
- "Launch GNOME System monitor": "启动 GNOME 系统监视器",
- "Toggle fallback launcher: anyrun": "切换备用启动器:anyrun",
- "Toggle fallback launcher: fuzzel": "切换备用启动器:fuzzel",
- "Initialization complete!": "初始化完成!",
- "Not found": "未找到",
- "Calling API": "调用 API",
- "Downloading image": "正在下载图片",
- "Finished!": "完成!",
- "Error": "错误",
- "Not found!": "未找到!",
- "Go to file url": "前往文件链接",
- "Save image": "保存图片",
- "Hoard": "保存",
- "Open externally": "在外部打开",
- "You are an assistant on a sidebar of a Wayland Linux desktop. Please always use a casual tone when answering your questions, unless requested otherwise or making writing suggestions. These are the steps you should take to respond to the user's queries:\n1. If it's a writing- or grammar-related question or a sentence in quotation marks, Please point out errors and correct when necessary using underlines, and make the writing more natural where appropriate without making too major changes. If you're given a sentence in quotes but is grammatically correct, explain briefly concepts that are uncommon.\n2. If it's a question about system tasks, give a bash command in a code block with brief explanation.\n3. Otherwise, when asked to summarize information or explaining concepts, you are should use bullet points and headings. For mathematics expressions, you *have to* use LaTeX within a code block with the language set as \"latex\". \nNote: Use casual language, be short, while ensuring the factual correctness of your response. If you are unsure or don’t have enough information to provide a confident answer, simply say “I don’t know” or “I’m not sure.”. \nThanks!": "你是 Wayland Linux 桌面侧边栏上的助手。除非有其他要求或提供建议,否则请始终保持轻松的语气回答问题。这是你回答用户查询的步骤:\n1. 如果是写作或语法相关的问题,或者引号中的句子,请指出错误并在必要时进行更正,使用下划线,并在适当的地方使写作更自然,不要进行太大更改。如果你给出的句子在引号中但语法正确,请简要解释不常见概念。\n2. 如果是关于系统任务的问题,请给出bash命令,并在代码块中简要说明。\n3. 否则,在总结信息或解释概念时,你应该使用项目符号和标题。对于数学表达式,你必须在代码块中使用 LaTeX,并将语言设置为\"latex\"。\n注意:使用轻松的语言,简洁,同时确保回答的事实正确性。如果你不确定或没有足够的信息来提供自信的答案,只需说“我不知道”或“我不确定”。\n谢谢!",
- "Feels like": "体感温度"
-}
diff --git a/.config/ags/init.js b/.config/ags/init.js
deleted file mode 100644
index 023043541..000000000
--- a/.config/ags/init.js
+++ /dev/null
@@ -1,53 +0,0 @@
-const { Gio, GLib } = imports.gi;
-import GtkSource from "gi://GtkSource?version=3.0";
-import App from 'resource:///com/github/Aylur/ags/app.js'
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'
-import { darkMode } from './modules/.miscutils/system.js';
-
-const CUSTOM_SOURCEVIEW_SCHEME_PATH = `${App.configDir}/assets/themes/sourceviewtheme${darkMode.value ? '' : '-light'}.xml`;
-
-export const COMPILED_STYLE_DIR = `${GLib.get_user_cache_dir()}/ags/user/generated`
-
-function loadSourceViewColorScheme(filePath) {
- // Read the XML file content
- const file = Gio.File.new_for_path(filePath);
- const [success, contents] = file.load_contents(null);
-
- if (!success) {
- logError('Failed to load the XML file.');
- return;
- }
-
- // Parse the XML content and set the Style Scheme
- const schemeManager = GtkSource.StyleSchemeManager.get_default();
- schemeManager.append_search_path(file.get_parent().get_path());
-}
-
-globalThis['handleStyles'] = (resetMusic) => {
- // Reset
- Utils.exec(`mkdir -p "${GLib.get_user_state_dir()}/ags/scss"`);
- if (resetMusic) {
- Utils.exec(`bash -c 'echo "" > ${GLib.get_user_state_dir()}/ags/scss/_musicwal.scss'`); // reset music styles
- Utils.exec(`bash -c 'echo "" > ${GLib.get_user_state_dir()}/ags/scss/_musicmaterial.scss'`); // reset music styles
- }
- // Generate overrides
- let lightdark = darkMode.value ? "dark" : "light";
- Utils.writeFileSync(
- `
-@mixin symbolic-icon {
- -gtk-icon-theme: '${userOptions.icons.symbolicIconTheme[lightdark]}';
-}
-`,
- `${GLib.get_user_state_dir()}/ags/scss/_lib_mixins_overrides.scss`)
- // Compile and apply
- async function applyStyle() {
- Utils.exec(`mkdir -p ${COMPILED_STYLE_DIR}`);
- Utils.exec(`sass -I "${GLib.get_user_state_dir()}/ags/scss" -I "${App.configDir}/scss/fallback" "${App.configDir}/scss/main.scss" "${COMPILED_STYLE_DIR}/style.css"`);
- App.resetCss();
- App.applyCss(`${COMPILED_STYLE_DIR}/style.css`);
- console.log('[LOG] Styles loaded')
- }
- applyStyle().then(() => {
- loadSourceViewColorScheme(CUSTOM_SOURCEVIEW_SCHEME_PATH);
- }).catch(print);
-}
diff --git a/.config/ags/modules/.commondata/hyprlanddata.js b/.config/ags/modules/.commondata/hyprlanddata.js
deleted file mode 100644
index 395f2cd1b..000000000
--- a/.config/ags/modules/.commondata/hyprlanddata.js
+++ /dev/null
@@ -1,33 +0,0 @@
-const { Gdk } = imports.gi;
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { execAsync, exec } = Utils;
-
-export let monitors;
-
-// Mixes with Gdk monitor size cuz it reports monitor size scaled
-async function updateStuff() {
- monitors = JSON.parse(exec('hyprctl monitors -j'))
- const display = Gdk.Display.get_default();
- monitors.forEach((monitor, i) => {
- const gdkMonitor = display.get_monitor(i);
- monitor.realWidth = monitor.width;
- monitor.realHeight = monitor.height;
- if (userOptions.monitors.scaleMethod.toLowerCase == "gdk") {
- monitor.width = gdkMonitor.get_geometry().width;
- monitor.height = gdkMonitor.get_geometry().height;
- }
- else { // == "division"
- if (monitor.transform % 2 == 1) { // Vertical monitors (or horizontal monitor that's vertical by default...)
- monitor.width = Math.floor(monitor.realHeight / monitor.scale);
- monitor.height = Math.floor(monitor.realWidth / monitor.scale);
- }
- else {
- monitor.width = Math.ceil(monitor.realWidth / monitor.scale);
- monitor.height = Math.ceil(monitor.realHeight / monitor.scale);
- }
- }
- });
-}
-
-updateStuff().catch(print);
-
diff --git a/.config/ags/modules/.commondata/quotes.js b/.config/ags/modules/.commondata/quotes.js
deleted file mode 100644
index 7cea99075..000000000
--- a/.config/ags/modules/.commondata/quotes.js
+++ /dev/null
@@ -1,14 +0,0 @@
-export const quotes = [
- {
- quote: 'Nvidia, fuck you',
- author: 'Linus Torvalds',
- },
- {
- quote: 'reproducible system? cock and vagina?',
- author: 'vaxry',
- },
- {
- quote: "haha pointers hee hee i love pointe-\\\nProcess Vaxry exited with signal SIGSEGV",
- author: 'vaxry',
- }
-];
diff --git a/.config/ags/modules/.commondata/weather.js b/.config/ags/modules/.commondata/weather.js
deleted file mode 100644
index 57c34fb1b..000000000
--- a/.config/ags/modules/.commondata/weather.js
+++ /dev/null
@@ -1,94 +0,0 @@
-export const WWO_CODE = {
- "113": "Sunny",
- "116": "PartlyCloudy",
- "119": "Cloudy",
- "122": "VeryCloudy",
- "143": "Fog",
- "176": "LightShowers",
- "179": "LightSleetShowers",
- "182": "LightSleet",
- "185": "LightSleet",
- "200": "ThunderyShowers",
- "227": "LightSnow",
- "230": "HeavySnow",
- "248": "Fog",
- "260": "Fog",
- "263": "LightShowers",
- "266": "LightRain",
- "281": "LightSleet",
- "284": "LightSleet",
- "293": "LightRain",
- "296": "LightRain",
- "299": "HeavyShowers",
- "302": "HeavyRain",
- "305": "HeavyShowers",
- "308": "HeavyRain",
- "311": "LightSleet",
- "314": "LightSleet",
- "317": "LightSleet",
- "320": "LightSnow",
- "323": "LightSnowShowers",
- "326": "LightSnowShowers",
- "329": "HeavySnow",
- "332": "HeavySnow",
- "335": "HeavySnowShowers",
- "338": "HeavySnow",
- "350": "LightSleet",
- "353": "LightShowers",
- "356": "HeavyShowers",
- "359": "HeavyRain",
- "362": "LightSleetShowers",
- "365": "LightSleetShowers",
- "368": "LightSnowShowers",
- "371": "HeavySnowShowers",
- "374": "LightSleetShowers",
- "377": "LightSleet",
- "386": "ThunderyShowers",
- "389": "ThunderyHeavyRain",
- "392": "ThunderySnowShowers",
- "395": "HeavySnowShowers",
-}
-
-export const WEATHER_SYMBOL = {
- "Unknown": "air",
- "Cloudy": "cloud",
- "Fog": "foggy",
- "HeavyRain": "rainy",
- "HeavyShowers": "rainy",
- "HeavySnow": "snowing",
- "HeavySnowShowers": "snowing",
- "LightRain": "rainy",
- "LightShowers": "rainy",
- "LightSleet": "rainy",
- "LightSleetShowers": "rainy",
- "LightSnow": "cloudy_snowing",
- "LightSnowShowers": "cloudy_snowing",
- "PartlyCloudy": "partly_cloudy_day",
- "Sunny": "clear_day",
- "ThunderyHeavyRain": "thunderstorm",
- "ThunderyShowers": "thunderstorm",
- "ThunderySnowShowers": "thunderstorm",
- "VeryCloudy": "cloud",
-}
-
-export const NIGHT_WEATHER_SYMBOL = {
- "Unknown": "air",
- "Cloudy": "cloud",
- "Fog": "foggy",
- "HeavyRain": "rainy",
- "HeavyShowers": "rainy",
- "HeavySnow": "snowing",
- "HeavySnowShowers": "snowing",
- "LightRain": "rainy",
- "LightShowers": "rainy",
- "LightSleet": "rainy",
- "LightSleetShowers": "rainy",
- "LightSnow": "cloudy_snowing",
- "LightSnowShowers": "cloudy_snowing",
- "PartlyCloudy": "partly_cloudy_night",
- "Sunny": "clear_night",
- "ThunderyHeavyRain": "thunderstorm",
- "ThunderyShowers": "thunderstorm",
- "ThunderySnowShowers": "thunderstorm",
- "VeryCloudy": "cloud",
-}
\ No newline at end of file
diff --git a/.config/ags/modules/.commonwidgets/cairo_circularprogress.js b/.config/ags/modules/.commonwidgets/cairo_circularprogress.js
deleted file mode 100644
index 83c184227..000000000
--- a/.config/ags/modules/.commonwidgets/cairo_circularprogress.js
+++ /dev/null
@@ -1,106 +0,0 @@
-const { Gtk } = imports.gi;
-const Lang = imports.lang;
-import Widget from 'resource:///com/github/Aylur/ags/widget.js'
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'
-
-// -- Styling --
-// min-height for diameter
-// min-width for trough stroke
-// padding for space between trough and progress
-// margin for space between widget and parent
-// background-color for trough color
-// color for progress color
-// -- Usage --
-// font size for progress value (0-100px) (hacky i know, but i want animations)
-export const AnimatedCircProg = ({
- initFrom = 0,
- initTo = 0,
- initAnimTime = 2900,
- initAnimPoints = 1,
- extraSetup = () => { },
- ...rest
-}) => Widget.DrawingArea({
- ...rest,
- css: `${initFrom != initTo ? 'font-size: ' + initFrom + 'px; transition: ' + initAnimTime + 'ms linear;' : ''}`,
- setup: (area) => {
- const styleContext = area.get_style_context();
- const width = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
- const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
- const padding = styleContext.get_padding(Gtk.StateFlags.NORMAL).left;
- const marginLeft = styleContext.get_margin(Gtk.StateFlags.NORMAL).left;
- const marginRight = styleContext.get_margin(Gtk.StateFlags.NORMAL).right;
- const marginTop = styleContext.get_margin(Gtk.StateFlags.NORMAL).top;
- const marginBottom = styleContext.get_margin(Gtk.StateFlags.NORMAL).bottom;
- area.set_size_request(width + marginLeft + marginRight, height + marginTop + marginBottom);
- area.connect('draw', Lang.bind(area, (area, cr) => {
- const styleContext = area.get_style_context();
- const width = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
- const height = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
- const padding = styleContext.get_padding(Gtk.StateFlags.NORMAL).left;
- const marginLeft = styleContext.get_margin(Gtk.StateFlags.NORMAL).left;
- const marginRight = styleContext.get_margin(Gtk.StateFlags.NORMAL).right;
- const marginTop = styleContext.get_margin(Gtk.StateFlags.NORMAL).top;
- const marginBottom = styleContext.get_margin(Gtk.StateFlags.NORMAL).bottom;
- area.set_size_request(width + marginLeft + marginRight, height + marginTop + marginBottom);
-
- const progressValue = styleContext.get_property('font-size', Gtk.StateFlags.NORMAL) / 100.0;
-
- const bg_stroke = styleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
- const fg_stroke = bg_stroke - padding;
- const radius = Math.min(width, height) / 2.0 - Math.max(bg_stroke, fg_stroke) / 2.0;
- const center_x = width / 2.0 + marginLeft;
- const center_y = height / 2.0 + marginTop;
- const start_angle = -Math.PI / 2.0;
- const end_angle = start_angle + (2 * Math.PI * progressValue);
- const start_x = center_x + Math.cos(start_angle) * radius;
- const start_y = center_y + Math.sin(start_angle) * radius;
- const end_x = center_x + Math.cos(end_angle) * radius;
- const end_y = center_y + Math.sin(end_angle) * radius;
-
- // Draw background
- const background_color = styleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
- cr.setSourceRGBA(background_color.red, background_color.green, background_color.blue, background_color.alpha);
- cr.arc(center_x, center_y, radius, 0, 2 * Math.PI);
- cr.setLineWidth(bg_stroke);
- cr.stroke();
-
- if (progressValue == 0) return;
-
- // Draw progress
- const color = styleContext.get_property('color', Gtk.StateFlags.NORMAL);
- cr.setSourceRGBA(color.red, color.green, color.blue, color.alpha);
- cr.arc(center_x, center_y, radius, start_angle, end_angle);
- cr.setLineWidth(fg_stroke);
- cr.stroke();
-
- // Draw rounded ends for progress arcs
- cr.setLineWidth(0);
- cr.arc(start_x, start_y, fg_stroke / 2, 0, 0 - 0.01);
- cr.fill();
- cr.arc(end_x, end_y, fg_stroke / 2, 0, 0 - 0.01);
- cr.fill();
- }));
-
- // Init animation
- if (initFrom != initTo) {
- area.css = `font-size: ${initFrom}px; transition: ${initAnimTime}ms linear;`;
- Utils.timeout(20, () => {
- area.css = `font-size: ${initTo}px;`;
- }, area)
- const transitionDistance = initTo - initFrom;
- const oneStep = initAnimTime / initAnimPoints;
- area.css = `
- font-size: ${initFrom}px;
- transition: ${oneStep}ms linear;
- `;
- for (let i = 0; i < initAnimPoints; i++) {
- Utils.timeout(Math.max(10, i * oneStep), () => {
- if(!area) return;
- area.css = `${initFrom != initTo ? 'font-size: ' + (initFrom + (transitionDistance / initAnimPoints * (i + 1))) + 'px;' : ''}`;
- });
- }
- }
- else area.css = 'font-size: 0px;';
- extraSetup(area);
- },
-})
\ No newline at end of file
diff --git a/.config/ags/modules/.commonwidgets/cairo_navigationindicator.js b/.config/ags/modules/.commonwidgets/cairo_navigationindicator.js
deleted file mode 100644
index fd8d5990f..000000000
--- a/.config/ags/modules/.commonwidgets/cairo_navigationindicator.js
+++ /dev/null
@@ -1,71 +0,0 @@
-const { Gtk } = imports.gi;
-const Lang = imports.lang;
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-
-// min-height/min-width for height/width
-// background-color/color for background/indicator color
-// padding for pad of indicator
-// font-size for selected index (0-based)
-export const NavigationIndicator = ({count, vertical, ...props}) => Widget.DrawingArea({
- ...props,
- setup: (area) => {
- const styleContext = area.get_style_context();
- const width = Math.max(styleContext.get_property('min-width', Gtk.StateFlags.NORMAL), area.get_allocated_width());
- const height = Math.max(styleContext.get_property('min-height', Gtk.StateFlags.NORMAL), area.get_allocated_height());
- area.set_size_request(width, height);
-
- area.connect('draw', Lang.bind(area, (area, cr) => {
- const styleContext = area.get_style_context();
- const width = Math.max(styleContext.get_property('min-width', Gtk.StateFlags.NORMAL), area.get_allocated_width());
- const height = Math.max(styleContext.get_property('min-height', Gtk.StateFlags.NORMAL), area.get_allocated_height());
- // console.log('allocated width/height:', area.get_allocated_width(), '/', area.get_allocated_height())
- area.set_size_request(width, height);
- const paddingLeft = styleContext.get_padding(Gtk.StateFlags.NORMAL).left;
- const paddingRight = styleContext.get_padding(Gtk.StateFlags.NORMAL).right;
- const paddingTop = styleContext.get_padding(Gtk.StateFlags.NORMAL).top;
- const paddingBottom = styleContext.get_padding(Gtk.StateFlags.NORMAL).bottom;
-
- const selectedCell = styleContext.get_property('font-size', Gtk.StateFlags.NORMAL);
-
- let cellWidth = width;
- let cellHeight = height;
- if (vertical) cellHeight /= count;
- else cellWidth /= count;
- const indicatorWidth = cellWidth - paddingLeft - paddingRight;
- const indicatorHeight = cellHeight - paddingTop - paddingBottom;
-
- const background_color = styleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
- const color = styleContext.get_property('color', Gtk.StateFlags.NORMAL);
- cr.setLineWidth(2);
- // Background
- cr.setSourceRGBA(background_color.red, background_color.green, background_color.blue, background_color.alpha);
- cr.rectangle(0, 0, width, height);
- cr.fill();
-
- // The indicator line
- cr.setSourceRGBA(color.red, color.green, color.blue, color.alpha);
- if (vertical) {
- cr.rectangle(paddingLeft, paddingTop + cellHeight * selectedCell + indicatorWidth / 2, indicatorWidth, indicatorHeight - indicatorWidth);
- cr.stroke();
- cr.rectangle(paddingLeft, paddingTop + cellHeight * selectedCell + indicatorWidth / 2, indicatorWidth, indicatorHeight - indicatorWidth);
- cr.fill();
- cr.arc(paddingLeft + indicatorWidth / 2, paddingTop + cellHeight * selectedCell + indicatorWidth / 2, indicatorWidth / 2, Math.PI, 2 * Math.PI);
- cr.fill();
- cr.arc(paddingLeft + indicatorWidth / 2, paddingTop + cellHeight * selectedCell + indicatorHeight - indicatorWidth / 2, indicatorWidth / 2, 0, Math.PI);
- cr.fill();
- }
- else {
- cr.rectangle(paddingLeft + cellWidth * selectedCell + indicatorHeight / 2, paddingTop, indicatorWidth - indicatorHeight, indicatorHeight);
- cr.stroke();
- cr.rectangle(paddingLeft + cellWidth * selectedCell + indicatorHeight / 2, paddingTop, indicatorWidth - indicatorHeight, indicatorHeight);
- cr.fill();
- cr.arc(paddingLeft + cellWidth * selectedCell + indicatorHeight / 2, paddingTop + indicatorHeight / 2, indicatorHeight / 2, 0.5 * Math.PI, 1.5 * Math.PI);
- cr.fill();
- cr.arc(paddingLeft + cellWidth * selectedCell + indicatorWidth - indicatorHeight / 2, paddingTop + indicatorHeight / 2, indicatorHeight / 2, -0.5 * Math.PI, 0.5 * Math.PI);
- cr.fill();
- }
- }))
- },
-})
-
-
diff --git a/.config/ags/modules/.commonwidgets/cairo_roundedcorner.js b/.config/ags/modules/.commonwidgets/cairo_roundedcorner.js
deleted file mode 100644
index 90c1cf07b..000000000
--- a/.config/ags/modules/.commonwidgets/cairo_roundedcorner.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-const { Gtk } = imports.gi;
-const Lang = imports.lang;
-
-export const RoundedCorner = (place, props) => Widget.DrawingArea({
- ...props,
- hpack: place.includes('left') ? 'start' : 'end',
- vpack: place.includes('top') ? 'start' : 'end',
- setup: (widget) => Utils.timeout(1, () => {
- const c = widget.get_style_context().get_property('background-color', Gtk.StateFlags.NORMAL);
- const r = widget.get_style_context().get_property('border-radius', Gtk.StateFlags.NORMAL);
- widget.set_size_request(r, r);
- widget.connect('draw', Lang.bind(widget, (widget, cr) => {
- const c = widget.get_style_context().get_property('background-color', Gtk.StateFlags.NORMAL);
- const r = widget.get_style_context().get_property('border-radius', Gtk.StateFlags.NORMAL);
- // const borderColor = widget.get_style_context().get_property('color', Gtk.StateFlags.NORMAL);
- // const borderWidth = widget.get_style_context().get_border(Gtk.StateFlags.NORMAL).left; // ur going to write border-width: something anyway
- widget.set_size_request(r, r);
-
- switch (place) {
- case 'topleft':
- cr.arc(r, r, r, Math.PI, 3 * Math.PI / 2);
- cr.lineTo(0, 0);
- break;
-
- case 'topright':
- cr.arc(0, r, r, 3 * Math.PI / 2, 2 * Math.PI);
- cr.lineTo(r, 0);
- break;
-
- case 'bottomleft':
- cr.arc(r, 0, r, Math.PI / 2, Math.PI);
- cr.lineTo(0, r);
- break;
-
- case 'bottomright':
- cr.arc(0, 0, r, 0, Math.PI / 2);
- cr.lineTo(r, r);
- break;
- }
-
- cr.closePath();
- cr.setSourceRGBA(c.red, c.green, c.blue, c.alpha);
- cr.fill();
- // cr.setLineWidth(borderWidth);
- // cr.setSourceRGBA(borderColor.red, borderColor.green, borderColor.blue, borderColor.alpha);
- // cr.stroke();
- }));
- }),
-});
\ No newline at end of file
diff --git a/.config/ags/modules/.commonwidgets/cairo_slider.js b/.config/ags/modules/.commonwidgets/cairo_slider.js
deleted file mode 100644
index eff9085c3..000000000
--- a/.config/ags/modules/.commonwidgets/cairo_slider.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-const { Gtk } = imports.gi;
-const Lang = imports.lang;
-
-export const AnimatedSlider = ({
- className,
- value,
- ...rest
-}) => {
- return Widget.DrawingArea({
- className: `${className}`,
- setup: (self) => {
- self.connect('draw', Lang.bind(self, (self, cr) => {
- const styleContext = self.get_style_context();
- const allocatedWidth = self.get_allocated_width();
- const allocatedHeight = self.get_allocated_height();
- console.log(allocatedHeight, allocatedWidth)
- const minWidth = styleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
- const minHeight = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
- const radius = styleContext.get_property('border-radius', Gtk.StateFlags.NORMAL);
- const bg = styleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
- const fg = styleContext.get_property('color', Gtk.StateFlags.NORMAL);
- const value = styleContext.get_property('font-size', Gtk.StateFlags.NORMAL) / 100;
- self.set_size_request(-1, minHeight);
- const width = allocatedHeight;
- const height = minHeight;
-
- cr.arc(radius, radius, radius, -1 * Math.PI, -0.5 * Math.PI); // Top-left
- cr.arc(width - radius, radius, radius, -0.5 * Math.PI, 0); // Top-right
- cr.arc(width - radius, height - radius, radius, 0, 0.5 * Math.PI); // Bottom-left
- cr.arc(radius, height - radius, radius, 0.5 * Math.PI, 1 * Math.PI); // Bottom-right
- cr.setSourceRGBA(bg.red, bg.green, bg.blue, bg.alpha);
- cr.closePath();
- cr.fill();
-
- // const valueWidth = width * value;
- // cr.arc(radius, radius, radius, -1 * Math.PI, -0.5 * Math.PI); // Top-left
- // cr.arc(valueWidth - radius, radius, radius, -0.5 * Math.PI, 0); // Top-right
- // cr.arc(valueWidth - radius, height - radius, radius, 0, 0.5 * Math.PI); // Bottom-left
- // cr.arc(radius, height - radius, radius, 0.5 * Math.PI, 1 * Math.PI); // Bottom-right
- // cr.setSourceRGBA(fg.red, fg.green, fg.blue, fg.alpha);
- // cr.closePath();
- // cr.fill();
-
- }));
- },
- ...rest,
- })
-}
diff --git a/.config/ags/modules/.commonwidgets/clickcloseregion.js b/.config/ags/modules/.commonwidgets/clickcloseregion.js
deleted file mode 100644
index e0aae79b0..000000000
--- a/.config/ags/modules/.commonwidgets/clickcloseregion.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import { monitors } from '../.commondata/hyprlanddata.js';
-const { Box, EventBox } = Widget;
-
-export const clickCloseRegion = ({ name, multimonitor = true, monitor = 0, expand = true, fillMonitor = '' }) => {
- return EventBox({
- child: Box({
- expand: expand,
- css: `
- min-width: ${fillMonitor.includes('h') ? monitors[monitor].width : 0}px;
- min-height: ${fillMonitor.includes('v') ? monitors[monitor].height : 0}px;
- `,
- }),
- setup: (self) => self.on('button-press-event', (self, event) => { // Any mouse button
- if (multimonitor) closeWindowOnAllMonitors(name);
- else App.closeWindow(name);
- }),
- })
-}
-
-export default clickCloseRegion;
-
diff --git a/.config/ags/modules/.commonwidgets/configwidgets.js b/.config/ags/modules/.commonwidgets/configwidgets.js
deleted file mode 100644
index 2b49a7d2f..000000000
--- a/.config/ags/modules/.commonwidgets/configwidgets.js
+++ /dev/null
@@ -1,298 +0,0 @@
-const { Gtk } = imports.gi;
-import Variable from 'resource:///com/github/Aylur/ags/variable.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-import { MaterialIcon } from './materialicon.js';
-import { setupCursorHover, setupCursorHoverHResize } from '../.widgetutils/cursorhover.js';
-const { Box, Button, EventBox, Label, Revealer, SpinButton } = Widget;
-
-// Basically M3 Switch
-// https://m3.material.io/components/switch/overview
-// onReset must be async
-export const ConfigToggle = ({
- icon, name, desc = '', initValue,
- expandWidget = true, resetButton = false,
- onChange = () => { }, extraSetup = () => { },
- onReset = () => { }, fetchValue = () => { },
- ...rest
-}) => {
- const enabled = Variable(initValue);
- const toggleIcon = Label({
- className: `icon-material txt-bold ${enabled.value ? '' : 'txt-poof'}`,
- label: `${enabled.value ? 'check' : ''}`,
- setup: (self) => self.hook(enabled, (self) => {
- self.toggleClassName('switch-fg-toggling-false', false);
- if (!enabled.value) {
- self.label = '';
- self.toggleClassName('txt-poof', true);
- }
- else Utils.timeout(1, () => {
- toggleIcon.label = 'check';
- toggleIcon.toggleClassName('txt-poof', false);
- })
- }),
- })
- const toggleButtonIndicator = Box({
- className: `switch-fg ${enabled.value ? 'switch-fg-true' : ''}`,
- vpack: 'center',
- hpack: 'start',
- homogeneous: true,
- children: [toggleIcon,],
- setup: (self) => self.hook(enabled, (self) => {
- self.toggleClassName('switch-fg-true', enabled.value);
- }),
- });
- const toggleButton = Box({
- hpack: 'end',
- vpack: 'center',
- className: `switch-bg ${enabled.value ? 'switch-bg-true' : ''}`,
- homogeneous: true,
- children: [toggleButtonIndicator],
- setup: (self) => self.hook(enabled, (self) => {
- self.toggleClassName('switch-bg-true', enabled.value);
- }),
- });
- const widgetContent = Box({
- tooltipText: desc,
- className: 'txt spacing-h-5',
- children: [
- ...(icon !== undefined ? [MaterialIcon(icon, 'norm', {vpack: 'center'})] : []),
- ...(name !== undefined ? [Label({
- vpack: 'center',
- className: 'txt txt-small',
- label: name,
- })] : []),
- ...(expandWidget ? [Box({ hexpand: true })] : []),
- toggleButton,
- ]
- });
- const interactionWrapper = Button({
- attribute: {
- enabled: enabled,
- toggle: (newValue) => {
- enabled.value = !enabled.value;
- onChange(interactionWrapper, enabled.value);
- }
- },
- child: widgetContent,
- onClicked: (self) => self.attribute.toggle(self),
- onHoverLost: () => { // mouse away
- toggleIcon.toggleClassName('switch-fg-toggling-false', false);
- if (enabled.value) toggleIcon.toggleClassName('txt-poof', false);
- },
- setup: (self) => {
- setupCursorHover(self);
- self.connect('pressed', () => { // mouse down
- toggleIcon.toggleClassName('txt-poof', true);
- toggleIcon.toggleClassName('switch-fg-true', false);
- if (!enabled.value) toggleIcon.toggleClassName('switch-fg-toggling-false', true);
- });
- extraSetup(self)
- },
- ...rest,
- });
- const wholeThing = Box({
- attribute: {
- 'enabled': enabled,
- },
- className: 'configtoggle-box spacing-h-5',
- children: [
- interactionWrapper,
- ...(resetButton ? [Button({
- className: 'configtoggle-reset',
- onClicked: (self) => {
- onReset(self).then(() => {
- enabled.value = fetchValue();
- }).catch(print);
- },
- child: MaterialIcon('settings_backup_restore', 'small'),
- setup: setupCursorHover,
- })] : []),
- ]
- });
- wholeThing.enabled = enabled;
- return wholeThing;
-}
-
-export const ConfigSegmentedSelection = ({
- icon, name, desc = '',
- options = [{ name: 'Option 1', value: 0 }, { name: 'Option 2', value: 1 }],
- initIndex = 0,
- onChange,
- ...rest
-}) => {
- let lastSelected = initIndex;
- let value = options[initIndex].value;
- const widget = Box({
- tooltipText: desc,
- className: 'segment-container',
- // homogeneous: true,
- children: options.map((option, id) => {
- const selectedIcon = Revealer({
- revealChild: id == initIndex,
- transition: 'slide_right',
- transitionDuration: userOptions.animations.durationSmall,
- child: MaterialIcon('check', 'norm')
- });
- return Button({
- setup: setupCursorHover,
- className: `segment-btn ${id == initIndex ? 'segment-btn-enabled' : ''}`,
- child: Box({
- hpack: 'center',
- className: 'spacing-h-5',
- children: [
- selectedIcon,
- Label({
- label: option.name,
- })
- ]
- }),
- onClicked: (self) => {
- value = option.value;
- const kids = widget.get_children();
- kids[lastSelected].toggleClassName('segment-btn-enabled', false);
- kids[lastSelected].get_children()[0].get_children()[0].revealChild = false;
- lastSelected = id;
- self.toggleClassName('segment-btn-enabled', true);
- selectedIcon.revealChild = true;
- onChange(option.value, option.name);
- }
- })
- }),
- ...rest,
- });
- return widget;
-
-}
-
-export const ConfigMulipleSelection = ({
- icon, name, desc = '',
- optionsArr = [
- [{ name: 'Option 1', value: 0 }, { name: 'Option 2', value: 1 }],
- [{ name: 'Option 3', value: 0 }, { name: 'Option 4', value: 1 }],
- ],
- initIndex = [0, 0],
- onChange,
- ...rest
-}) => {
- let lastSelected = initIndex;
- const widget = Box({
- tooltipText: desc,
- className: 'multipleselection-container spacing-v-3',
- vertical: true,
- children: optionsArr.map((options, grp) => Box({
- className: 'spacing-h-5',
- hpack: 'center',
- children: options.map((option, id) => Button({
- setup: setupCursorHover,
- className: `multipleselection-btn ${id == initIndex[1] && grp == initIndex[0] ? 'multipleselection-btn-enabled' : ''}`,
- label: option.name,
- onClicked: (self) => {
- const kidsg = widget.get_children();
- const kids = kidsg.flatMap(widget => widget.get_children());
- kids.forEach(kid => {
- kid.toggleClassName('multipleselection-btn-enabled', false);
- });
- lastSelected = id;
- self.toggleClassName('multipleselection-btn-enabled', true);
- onChange(option.value, option.name);
- }
- })),
- })),
- ...rest,
- });
- return widget;
-
-}
-
-export const ConfigGap = ({ vertical = true, size = 5, ...rest }) => Box({
- className: `gap-${vertical ? 'v' : 'h'}-${size}`,
- ...rest,
-})
-
-// Gtk SpinButton with value scrubbing gesture
-// scrubRatio is the ratio of changed value to drag distance in pixels
-// onReset must be async
-export const ConfigSpinButton = ({
- icon, name, desc = '', initValue,
- minValue = 0, maxValue = 100, step = 1,
- expandWidget = true, resetButton = false,
- scrubRatio = 1 / 20, roundValue = true,
- onChange = () => { }, extraSetup = () => { },
- onReset = () => { }, fetchValue = () => { },
- ...rest
-}) => {
- let resetLock = false;
- const value = Variable(initValue);
- const spinButton = SpinButton({
- className: 'spinbutton',
- range: [minValue, maxValue],
- increments: [step, step],
- onValueChanged: ({ value: newValue }) => {
- if (resetLock) return;
- value.value = newValue;
- onChange(spinButton, newValue);
- },
- // This funny line means: set value of the spinbutton to the value of the
- // Variable object called value that tracks the value of the widget
- value: value.value,
- });
- const widgetContent = Box({
- tooltipText: desc,
- className: 'txt spacing-h-5 configtoggle-box',
- children: [
- ...(icon !== undefined ? [MaterialIcon(icon, 'norm')] : []),
- ...(name !== undefined ? [Label({
- className: 'txt txt-small',
- label: name,
- })] : []),
- ...(expandWidget ? [Box({ hexpand: true })] : []),
- spinButton,
- ...(resetButton ? [Button({
- className: 'spinbutton-reset',
- onClicked: (self) => {
- onReset(self).then(() => {
- resetLock = true;
- const newValue = fetchValue();
- spinButton.value = newValue;
- value.value = newValue;
- resetLock = false;
- }).catch(print);
- },
- child: MaterialIcon('settings_backup_restore', 'small'),
- setup: setupCursorHover,
- })] : []),
- ],
- setup: (self) => {
- extraSetup(self);
- },
- ...rest,
- });
- const interactionWrapper = EventBox({
- child: widgetContent,
- setup: setupCursorHoverHResize,
- })
- const gesture = Gtk.GestureDrag.new(interactionWrapper);
- let gestureValueOnDragBegin;
- const wholeThing = Box({
- children: [interactionWrapper],
- setup: (self) => self
- .hook(gesture, (self) => {
- gestureValueOnDragBegin = value.value;
- }, 'drag-begin')
- .hook(gesture, (self) => {
- var offset_x = gesture.get_offset()[1];
- var offset_y = gesture.get_offset()[2];
- let newValue = gestureValueOnDragBegin + (offset_x * scrubRatio);
- if (roundValue) newValue = Math.round(newValue);
- if (newValue !== spinButton.value) {
- spinButton.value = newValue;
- }
- }, 'drag-update')
- .hook(gesture, (self) => {
-
- }, 'drag-end')
- });
- wholeThing.enabled = value;
- return wholeThing;
-}
\ No newline at end of file
diff --git a/.config/ags/modules/.commonwidgets/configwidgets_apps.js b/.config/ags/modules/.commonwidgets/configwidgets_apps.js
deleted file mode 100644
index 3bf7ce712..000000000
--- a/.config/ags/modules/.commonwidgets/configwidgets_apps.js
+++ /dev/null
@@ -1,154 +0,0 @@
-const { GLib } = imports.gi;
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { execAsync, exec } = Utils;
-
-import { getNestedProperty, updateNestedProperty } from "../.miscutils/objects.js";
-import { ConfigSpinButton, ConfigToggle } from "./configwidgets.js";
-
-const AGS_CONFIG_FILE = `${App.configDir}/user_options.jsonc`;
-const HYPRLAND_CONFIG_FILE = `${GLib.get_user_config_dir()}/hypr/custom/general.conf`;
-
-export const AgsToggle = ({
- icon, name, desc = null,
- option, resetButton = true, save = true,
- extraOnChange = () => { }, extraOnReset = () => { },
- ...rest
-}) => ConfigToggle({
- icon: icon,
- name: name,
- desc: `${desc}\n\n${option}\nEdit in ${AGS_CONFIG_FILE}`,
- resetButton: resetButton,
- initValue: getNestedProperty(userOptions, option),
- fetchValue: () => getNestedProperty(userOptions, option),
- onChange: (self, newValue) => {
- updateNestedProperty(userOptions, option, newValue);
- if (save) execAsync(['bash', '-c', `${App.configDir}/scripts/ags/agsconfigurator.py \
- --key ${option} \
- --value ${newValue} \
- --file ${AGS_CONFIG_FILE}`
- ]).catch(print);
- extraOnChange(self, newValue);
- },
- onReset: async (self) => {
- updateNestedProperty(userOptions, option,
- getNestedProperty(userOptionsDefaults, option));
- if (save) exec(`bash -c '${App.configDir}/scripts/ags/agsconfigurator.py \
- --key ${option} \
- --reset \
- --file ${AGS_CONFIG_FILE}'`);
- extraOnReset(self);
- },
- ...rest
-});
-
-export const AgsSpinButton = ({
- icon, name, desc = null,
- option, resetButton = true,
- save = true, extraOnChange = () => { }, extraOnReset = () => { },
- ...rest
-}) => ConfigSpinButton({
- icon: icon,
- name: name,
- desc: `${desc}\n\n${option}\nEdit in ${AGS_CONFIG_FILE}`,
- resetButton: resetButton,
- initValue: getNestedProperty(userOptions, option),
- fetchValue: () => getNestedProperty(userOptions, option),
- step: 10, minValue: 0, maxValue: 1000,
- onChange: (self, newValue) => {
- updateNestedProperty(userOptions, option, newValue);
- if (save) execAsync(['bash', '-c', `${App.configDir}/scripts/ags/agsconfigurator.py \
- --key ${option} \
- --value ${newValue} \
- --file ${AGS_CONFIG_FILE}`
- ]).catch(print);
- extraOnChange(self, newValue);
- },
- onReset: async () => {
- updateNestedProperty(userOptions, option,
- getNestedProperty(userOptionsDefaults, option));
- if (save) exec(`bash -c '${App.configDir}/scripts/ags/agsconfigurator.py \
- --key ${option} \
- --reset \
- --file ${AGS_CONFIG_FILE}'`);
- extraOnReset(self);
- },
- ...rest,
-});
-
-export const HyprlandToggle = ({
- icon, name, desc = null,
- option, resetButton = true,
- enableValue = 1, disableValue = 0,
- extraOnChange = () => { }, extraOnReset = () => { }, save = true
-}) => ConfigToggle({
- icon: icon,
- name: name,
- desc: `${desc}\n\n${option}\nEdit in ${HYPRLAND_CONFIG_FILE}`,
- resetButton: resetButton,
- initValue: JSON.parse(exec(`hyprctl getoption -j ${option}`))["int"] != 0,
- fetchValue: () => JSON.parse(exec(`hyprctl getoption -j ${option}`))["int"] != 0,
- onChange: (self, newValue) => {
- if (save)
- execAsync(['bash', '-c', `${App.configDir}/scripts/hyprland/hyprconfigurator.py \
- --key ${option} \
- --value ${newValue ? enableValue : disableValue} \
- --file ${HYPRLAND_CONFIG_FILE}`
- ]).catch(print);
-
- else
- execAsync(['hyprctl', 'keyword', option, `${newValue ? enableValue : disableValue}`]).catch(print);
-
- extraOnChange(self, newValue);
- },
- onReset: async (self) => {
- if (save)
- exec(`bash -c '${App.configDir}/scripts/hyprland/hyprconfigurator.py \
- --key ${option} \
- --reset \
- --file "${HYPRLAND_CONFIG_FILE}"'`);
-
- else
- exec('hyprctl reload');
- extraOnReset(self);
- },
-});
-
-export const HyprlandSpinButton = ({
- icon, name, desc = null,
- option, resetButton = true, save = true,
- extraOnChange = () => { }, extraOnReset = () => { },
- ...rest
-}) => ConfigSpinButton({
- icon: icon,
- name: name,
- desc: `${desc}\n\n${option}\nEdit in ${HYPRLAND_CONFIG_FILE}`,
- resetButton: resetButton,
- initValue: Number(JSON.parse(exec(`hyprctl getoption -j ${option}`))["int"]),
- fetchValue: () => Number(JSON.parse(exec(`hyprctl getoption -j ${option}`))["int"]),
- onChange: (self, newValue) => {
- if (save)
- execAsync(['bash', '-c', `${App.configDir}/scripts/hyprland/hyprconfigurator.py \
- --key ${option} \
- --value ${newValue} \
- --file ${HYPRLAND_CONFIG_FILE}`
- ]).catch(print);
-
- else
- execAsync(['hyprctl', 'keyword', option, `${newValue}`]).catch(print);
-
- extraOnChange(self, newValue);
- },
- onReset: async (self) => {
- if (save)
- exec(`bash -c '${App.configDir}/scripts/hyprland/hyprconfigurator.py \
- --key ${option} \
- --reset \
- --file "${HYPRLAND_CONFIG_FILE}"'`);
-
- else
- exec('hyprctl reload');
- extraOnReset(self);
- },
- ...rest,
-});
-
diff --git a/.config/ags/modules/.commonwidgets/materialicon.js b/.config/ags/modules/.commonwidgets/materialicon.js
deleted file mode 100644
index 029f0ede6..000000000
--- a/.config/ags/modules/.commonwidgets/materialicon.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-
-export const MaterialIcon = (icon, size, props = {}) => Widget.Label({
- className: `icon-material txt-${size}`,
- label: icon,
- ...props,
-})
diff --git a/.config/ags/modules/.commonwidgets/notification.js b/.config/ags/modules/.commonwidgets/notification.js
deleted file mode 100644
index b9486a2f0..000000000
--- a/.config/ags/modules/.commonwidgets/notification.js
+++ /dev/null
@@ -1,505 +0,0 @@
-// This file is for the actual widget for each single notification
-const { GLib, Gdk, Gtk } = imports.gi;
-import Widget from 'resource:///com/github/Aylur/ags/widget.js'
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'
-const { Box, EventBox, Icon, Overlay, Label, Button, Revealer } = Widget;
-import { MaterialIcon } from './materialicon.js';
-import { setupCursorHover } from "../.widgetutils/cursorhover.js";
-import { AnimatedCircProg } from "./cairo_circularprogress.js";
-
-function guessMessageType(summary) {
- const keywordsToTypes = {
- 'reboot': 'restart_alt',
- 'recording': 'screen_record',
- 'battery': 'power',
- 'power': 'power',
- 'screenshot': 'screenshot_monitor',
- 'welcome': 'waving_hand',
- 'time': 'scheduleb',
- 'installed': 'download',
- 'update': 'update',
- 'ai response': 'neurology',
- 'startswith:file': 'folder_copy', // Declarative startsWith check
- };
-
- const lowerSummary = summary.toLowerCase();
-
- for (const [keyword, type] of Object.entries(keywordsToTypes)) {
- if (keyword.startsWith('startswith:')) {
- const startsWithKeyword = keyword.replace('startswith:', '');
- if (lowerSummary.startsWith(startsWithKeyword)) {
- return type;
- }
- } else if (lowerSummary.includes(keyword)) {
- return type;
- }
- }
-
- return 'chat';
-}
-
-function processNotificationBody(body, appEntry) {
- let processedBody = body;
- if (appEntry?.toLowerCase().includes('chrome')) {
- processedBody = body.split('\n\n').slice(1).join('\n\n');
- }
- processedBody = processedBody.replace(/<[^>]*>/g, '');
- return processedBody;
-}
-
-const getFriendlyNotifTimeString = (timeObject) => {
- const messageTime = GLib.DateTime.new_from_unix_local(timeObject);
- const oneMinuteAgo = GLib.DateTime.new_now_local().add_seconds(-60);
- if (messageTime.compare(oneMinuteAgo) > 0)
- return getString('Now');
- else if (messageTime.get_day_of_year() == GLib.DateTime.new_now_local().get_day_of_year())
- return messageTime.format(userOptions.time.format);
- else if (messageTime.get_day_of_year() == GLib.DateTime.new_now_local().get_day_of_year() - 1)
- return getString('Yesterday');
- else
- return messageTime.format(userOptions.time.dateFormat);
-}
-
-const NotificationIcon = (notifObject) => {
-
- if (notifObject.hints?.image_path?.deepUnpack) {
- const imagePath = notifObject.hints.image_path.deepUnpack();
- return Box({
- valign: Gtk.Align.CENTER,
- hexpand: false,
- className: 'notif-icon',
- css: `
- background-image: url("${imagePath}");
- background-size: auto 100%;
- background-repeat: no-repeat;
- background-position: center;
- `,
- });
- }
-
- if (notifObject.image) {
- return Box({
- valign: Gtk.Align.CENTER,
- hexpand: false,
- className: 'notif-icon',
- css: `
- background-image: url("${notifObject.image}");
- background-size: auto 100%;
- background-repeat: no-repeat;
- background-position: center;
- `,
- });
- }
-
- let icon = 'NO_ICON';
- if (Utils.lookUpIcon(notifObject.appIcon))
- icon = notifObject.appIcon;
- if (Utils.lookUpIcon(notifObject.appEntry))
- icon = notifObject.appEntry;
-
- return Box({
- vpack: 'center',
- hexpand: false,
- className: `notif-icon notif-icon-material-${notifObject.urgency}`,
- homogeneous: true,
- children: [
- (icon != 'NO_ICON' ?
- Icon({
- vpack: 'center',
- icon: icon,
- })
- :
- MaterialIcon(`${notifObject.urgency == 'critical' ? 'release_alert' : guessMessageType(notifObject.summary.toLowerCase())}`, 'hugerass', {
- hexpand: true,
- })
- )
- ],
- });
-};
-
-export default ({
- notifObject,
- isPopup = false,
- props = {},
-} = {}) => {
- const popupTimeout = notifObject.timeout || (notifObject.urgency == 'critical' ? 8000 : 3000);
- const command = (isPopup ?
- () => notifObject.dismiss() :
- () => notifObject.close()
- )
- const destroyWithAnims = () => {
- widget.sensitive = false;
- notificationBox.setCss(middleClickClose);
- Utils.timeout(userOptions.animations.durationSmall, () => {
- if (wholeThing) wholeThing.revealChild = false;
- }, wholeThing);
- Utils.timeout(userOptions.animations.durationSmall * 2, () => {
- command();
- if (wholeThing) {
- wholeThing.destroy();
- wholeThing = null;
- }
- }, wholeThing);
- }
- const widget = EventBox({
- onHover: (self) => {
- self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grab'));
- if (!wholeThing.attribute.hovered)
- wholeThing.attribute.hovered = true;
- },
- onHoverLost: (self) => {
- self.window.set_cursor(null);
- if (wholeThing.attribute.hovered)
- wholeThing.attribute.hovered = false;
- if (isPopup) {
- command();
- }
- },
- onMiddleClick: (self) => {
- destroyWithAnims();
- },
- onSecondaryClick: (self) => {
- expanded = !expanded;
- notifTextPreview.revealChild = !expanded;
- notifTextExpanded.revealChild = expanded;
- notifExpandButton.child.label = `expand_${expanded ? 'less' : 'more'}`;
- },
- setup: (self) => {
- self.on("button-press-event", () => {
- wholeThing.attribute.held = true;
- notificationContent.toggleClassName(`${isPopup ? 'popup-' : ''}notif-clicked-${notifObject.urgency}`, true);
- Utils.timeout(800, () => {
- if (wholeThing?.attribute.held) {
- Utils.execAsync(['wl-copy', `${notifObject.body}`]).catch(print);
- notifTextSummary.label = notifObject.summary + " (copied)";
- Utils.timeout(3000, () => notifTextSummary.label = notifObject.summary)
- }
- })
- }).on("button-release-event", () => {
- wholeThing.attribute.held = false;
- notificationContent.toggleClassName(`${isPopup ? 'popup-' : ''}notif-clicked-${notifObject.urgency}`, false);
- })
- }
- });
- let wholeThing = Revealer({
- attribute: {
- 'close': undefined,
- 'destroyWithAnims': destroyWithAnims,
- 'dragging': false,
- 'held': false,
- 'hovered': false,
- 'id': notifObject.id,
- },
- revealChild: false,
- transition: 'slide_down',
- transitionDuration: userOptions.animations.durationLarge,
- child: Box({ // Box to make sure css-based spacing works
- homogeneous: true,
- }),
- });
-
- const display = Gdk.Display.get_default();
- const notifTextPreview = Revealer({
- transition: 'slide_down',
- transitionDuration: userOptions.animations.durationSmall,
- revealChild: true,
- child: Label({
- xalign: 0,
- className: `txt-smallie notif-body-${notifObject.urgency}`,
- useMarkup: true,
- xalign: 0,
- justify: Gtk.Justification.LEFT,
- maxWidthChars: 1,
- truncate: 'end',
- label: processNotificationBody(notifObject.body, notifObject.appEntry).split("\n")[0]
- }),
- });
- const notifTextExpanded = Revealer({
- transition: 'slide_up',
- transitionDuration: userOptions.animations.durationSmall,
- revealChild: false,
- child: Box({
- vertical: true,
- className: 'spacing-v-10',
- children: [
- Label({
- xalign: 0,
- className: `txt-smallie notif-body-${notifObject.urgency}`,
- useMarkup: true,
- xalign: 0,
- justify: Gtk.Justification.LEFT,
- maxWidthChars: 1,
- wrap: true,
- label: processNotificationBody(notifObject.body, notifObject.appEntry)
- }),
- Box({
- className: 'notif-actions spacing-h-5',
- children: [
- Button({
- hexpand: true,
- className: `notif-action notif-action-${notifObject.urgency}`,
- onClicked: () => destroyWithAnims(),
- setup: setupCursorHover,
- child: Label({
- label: getString('Close'),
- }),
- }),
- ...notifObject.actions.map(action => Widget.Button({
- hexpand: true,
- className: `notif-action notif-action-${notifObject.urgency}`,
- onClicked: () => notifObject.invoke(action.id),
- setup: setupCursorHover,
- child: Label({
- label: action.label,
- }),
- }))
- ],
- })
- ]
- }),
- });
- const notifIcon = Box({
- vpack: 'start',
- homogeneous: true,
- children: [
- Overlay({
- child: NotificationIcon(notifObject),
- overlays: isPopup ? [AnimatedCircProg({
- className: `notif-circprog-${notifObject.urgency}`,
- vpack: 'center', hpack: 'center',
- initFrom: (isPopup ? 100 : 0),
- initTo: 0,
- initAnimTime: popupTimeout,
- })] : [],
- }),
- ]
- });
-
- const notifTextSummary = Label({
- xalign: 0,
- className: 'txt-small txt-semibold titlefont',
- justify: Gtk.Justification.LEFT,
- hexpand: true,
- maxWidthChars: 1,
- truncate: 'end',
- ellipsize: 3,
- useMarkup: notifObject.summary.startsWith('<'),
- label: notifObject.summary,
- });
- const initTimeString = getFriendlyNotifTimeString(notifObject.time);
- const notifTextBody = Label({
- vpack: 'center',
- justification: 'right',
- className: 'txt-smaller txt-semibold',
- label: initTimeString,
- setup: initTimeString == 'Now' ? (self) => {
- let id = Utils.timeout(60000, () => {
- self.label = getFriendlyNotifTimeString(notifObject.time);
- id = null;
- });
- self.connect('destroy', () => { if (id) GLib.source_remove(id) });
- } : () => { },
- });
- const notifText = Box({
- valign: Gtk.Align.CENTER,
- vertical: true,
- hexpand: true,
- children: [
- Box({
- children: [
- notifTextSummary,
- notifTextBody,
- ]
- }),
- notifTextPreview,
- notifTextExpanded,
- ]
- });
- const notifExpandButton = Button({
- vpack: 'start',
- className: 'notif-expand-btn',
- onClicked: (self) => {
- if (notifTextPreview.revealChild) { // Expanding...
- notifTextPreview.revealChild = false;
- notifTextExpanded.revealChild = true;
- self.child.label = 'expand_less';
- expanded = true;
- }
- else {
- notifTextPreview.revealChild = true;
- notifTextExpanded.revealChild = false;
- self.child.label = 'expand_more';
- expanded = false;
- }
- },
- child: MaterialIcon('expand_more', 'norm', {
- vpack: 'center',
- }),
- setup: setupCursorHover,
- });
- const notificationContent = Box({
- ...props,
- className: `${isPopup ? 'popup-' : ''}notif-${notifObject.urgency} spacing-h-10`,
- children: [
- notifIcon,
- Box({
- className: 'spacing-h-5',
- children: [
- notifText,
- notifExpandButton,
- ]
- })
- ]
- })
-
- // Gesture stuff
- const gesture = Gtk.GestureDrag.new(widget);
- var initDirX = 0;
- var initDirVertical = -1; // -1: unset, 0: horizontal, 1: vertical
- var expanded = false;
- // in px
- const startMargin = 0;
- const MOVE_THRESHOLD = 10;
- const DRAG_CONFIRM_THRESHOLD = 100;
- // in rem
- const maxOffset = 10.227;
- const endMargin = 20.455;
- const disappearHeight = 6.818;
- const leftAnim1 = `transition: ${userOptions.animations.durationSmall}ms cubic-bezier(0.05, 0.7, 0.1, 1);
- margin-left: -${Number(maxOffset + endMargin)}rem;
- margin-right: ${Number(maxOffset + endMargin)}rem;
- opacity: 0;`;
-
- const rightAnim1 = `transition: ${userOptions.animations.durationSmall}ms cubic-bezier(0.05, 0.7, 0.1, 1);
- margin-left: ${Number(maxOffset + endMargin)}rem;
- margin-right: -${Number(maxOffset + endMargin)}rem;
- opacity: 0;`;
-
- const middleClickClose = `transition: ${userOptions.animations.durationSmall}ms cubic-bezier(0.85, 0, 0.15, 1);
- margin-left: ${Number(maxOffset + endMargin)}rem;
- margin-right: -${Number(maxOffset + endMargin)}rem;
- opacity: 0;`;
-
- const notificationBox = Box({
- attribute: {
- 'leftAnim1': leftAnim1,
- 'rightAnim1': rightAnim1,
- 'middleClickClose': middleClickClose,
- 'ready': false,
- },
- homogeneous: true,
- children: [notificationContent],
- setup: (self) => self
- .hook(gesture, self => {
- var offset_x = gesture.get_offset()[1];
- var offset_y = gesture.get_offset()[2];
- // Which dir?
- if (initDirVertical == -1) {
- if (Math.abs(offset_y) > MOVE_THRESHOLD)
- initDirVertical = 1;
- if (initDirX == 0 && Math.abs(offset_x) > MOVE_THRESHOLD) {
- initDirVertical = 0;
- initDirX = (offset_x > 0 ? 1 : -1);
- }
- }
- // Horizontal drag
- if (initDirVertical == 0 && offset_x > MOVE_THRESHOLD) {
- if (initDirX < 0)
- self.setCss(`margin-left: 0px; margin-right: 0px;`);
- else
- self.setCss(`
- margin-left: ${Number(offset_x + startMargin - MOVE_THRESHOLD)}px;
- margin-right: -${Number(offset_x + startMargin - MOVE_THRESHOLD)}px;
- `);
- }
- else if (initDirVertical == 0 && offset_x < -MOVE_THRESHOLD) {
- if (initDirX > 0)
- self.setCss(`margin-left: 0px; margin-right: 0px;`);
- else {
- offset_x = Math.abs(offset_x);
- self.setCss(`
- margin-right: ${Number(offset_x + startMargin - MOVE_THRESHOLD)}px;
- margin-left: -${Number(offset_x + startMargin - MOVE_THRESHOLD)}px;
- `);
- }
- }
- // Update dragging
- wholeThing.attribute.dragging = Math.abs(offset_x) > MOVE_THRESHOLD;
- if (Math.abs(offset_x) > MOVE_THRESHOLD ||
- Math.abs(offset_y) > MOVE_THRESHOLD) wholeThing.attribute.held = false;
- widget.window?.set_cursor(Gdk.Cursor.new_from_name(display, 'grabbing'));
- // Vertical drag
- if (initDirVertical == 1 && offset_y > MOVE_THRESHOLD && !expanded) {
- notifTextPreview.revealChild = false;
- notifTextExpanded.revealChild = true;
- expanded = true;
- notifExpandButton.child.label = 'expand_less';
- }
- else if (initDirVertical == 1 && offset_y < -MOVE_THRESHOLD && expanded) {
- notifTextPreview.revealChild = true;
- notifTextExpanded.revealChild = false;
- expanded = false;
- notifExpandButton.child.label = 'expand_more';
- }
-
- }, 'drag-update')
- .hook(gesture, self => {
- if (!self.attribute.ready) {
- wholeThing.revealChild = true;
- self.attribute.ready = true;
- return;
- }
- const offset_h = gesture.get_offset()[1];
-
- if (Math.abs(offset_h) > DRAG_CONFIRM_THRESHOLD && offset_h * initDirX > 0) {
- if (offset_h > 0) {
- self.setCss(rightAnim1);
- widget.sensitive = false;
- }
- else {
- self.setCss(leftAnim1);
- widget.sensitive = false;
- }
- Utils.timeout(userOptions.animations.durationSmall, () => {
- if (wholeThing) wholeThing.revealChild = false;
- }, wholeThing);
- Utils.timeout(userOptions.animations.durationSmall * 2, () => {
- command();
- if (wholeThing) {
- wholeThing.destroy();
- wholeThing = null;
- }
- }, wholeThing);
- }
- else {
- self.setCss(`transition: ${userOptions.animations.durationSmall}ms cubic-bezier(0.05, 0.7, 0.1, 1), opacity ${userOptions.animations.durationSmall}ms cubic-bezier(0.05, 0.7, 0.1, 1);
- margin-left: ${startMargin}px;
- margin-right: ${startMargin}px;
- margin-bottom: unset; margin-top: unset;
- opacity: 1;`);
- if (widget.window)
- widget.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grab'));
-
- wholeThing.attribute.dragging = false;
- }
- initDirX = 0;
- initDirVertical = -1;
- }, 'drag-end')
- ,
- })
- widget.add(notificationBox);
- wholeThing.child.children = [widget];
- if (isPopup) Utils.timeout(popupTimeout, () => {
- if (wholeThing && !wholeThing.attribute.hovered) {
- wholeThing.revealChild = false;
- Utils.timeout(userOptions.animations.durationSmall, () => {
- if (wholeThing) {
- wholeThing.destroy();
- wholeThing = null;
- }
- command();
- }, wholeThing);
- }
- })
- return wholeThing;
-}
diff --git a/.config/ags/modules/.commonwidgets/statusicons.js b/.config/ags/modules/.commonwidgets/statusicons.js
deleted file mode 100644
index 11b4e1769..000000000
--- a/.config/ags/modules/.commonwidgets/statusicons.js
+++ /dev/null
@@ -1,316 +0,0 @@
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Audio from 'resource:///com/github/Aylur/ags/service/audio.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-
-import { MaterialIcon } from './materialicon.js';
-import Bluetooth from 'resource:///com/github/Aylur/ags/service/bluetooth.js';
-import Network from 'resource:///com/github/Aylur/ags/service/network.js';
-import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
-import { languages } from './statusicons_languages.js';
-
-// A guessing func to try to support langs not listed in data/languages.js
-function isLanguageMatch(abbreviation, word) {
- const lowerAbbreviation = abbreviation.toLowerCase();
- const lowerWord = word.toLowerCase();
- let j = 0;
- for (let i = 0; i < lowerWord.length; i++) {
- if (lowerWord[i] === lowerAbbreviation[j]) {
- j++;
- }
- if (j === lowerAbbreviation.length) {
- return true;
- }
- }
- return false;
-}
-
-export const MicMuteIndicator = () => Widget.Revealer({
- transition: 'slide_left',
- transitionDuration: userOptions.animations.durationSmall,
- revealChild: false,
- setup: (self) => self.hook(Audio, (self) => {
- self.revealChild = Audio.microphone?.stream?.isMuted;
- }),
- child: MaterialIcon('mic_off', 'norm'),
-});
-
-export const NotificationIndicator = (notifCenterName = 'sideright') => {
- const widget = Widget.Revealer({
- transition: 'slide_left',
- transitionDuration: userOptions.animations.durationSmall,
- revealChild: false,
- setup: (self) => self
- .hook(Notifications, (self, id) => {
- if (!id || Notifications.dnd) return;
- if (!Notifications.getNotification(id)) return;
- self.revealChild = true;
- }, 'notified')
- .hook(App, (self, currentName, visible) => {
- if (visible && currentName === notifCenterName) {
- self.revealChild = false;
- }
- })
- ,
- child: Widget.Box({
- children: [
- MaterialIcon('notifications', 'norm'),
- Widget.Label({
- className: 'txt-small titlefont',
- attribute: {
- unreadCount: 0,
- update: (self) => self.label = `${self.attribute.unreadCount}`,
- },
- setup: (self) => self
- .hook(Notifications, (self, id) => {
- if (!id || Notifications.dnd) return;
- if (!Notifications.getNotification(id)) return;
- self.attribute.unreadCount++;
- self.attribute.update(self);
- }, 'notified')
- .hook(App, (self, currentName, visible) => {
- if (visible && currentName === notifCenterName) {
- self.attribute.unreadCount = 0;
- self.attribute.update(self);
- }
- })
- ,
- })
- ]
- })
- });
- return widget;
-}
-
-export const BluetoothIndicator = () => Widget.Stack({
- transition: 'slide_up_down',
- transitionDuration: userOptions.animations.durationSmall,
- children: {
- 'disabled': Widget.Label({ className: 'txt-norm icon-material', label: 'bluetooth_disabled' }),
- 'enabled': Widget.Label({ className: 'txt-norm icon-material', label: 'bluetooth' }),
- 'connected': Widget.Label({ className: 'txt-norm icon-material', label: 'bluetooth_connected' }),
- },
- setup: (self) =>
- self.hook(Bluetooth, (stack) => {
- if (!Bluetooth.enabled) {
- stack.shown = 'disabled';
- } else if (Bluetooth.connected_devices.length === 0) {
- stack.shown = 'enabled';
- } else if (Bluetooth.connected_devices.length > 0) {
- stack.shown = 'connected';
- }
- }),
-});
-
-const BluetoothDevices = () => Widget.Box({
- className: 'spacing-h-5',
- setup: self => self.hook(Bluetooth, self => {
- self.children = Bluetooth.connected_devices.map((device) => {
- return Widget.Box({
- className: 'bar-bluetooth-device spacing-h-5',
- vpack: 'center',
- tooltipText: device.name,
- children: [
- Widget.Icon(`${device.iconName}-symbolic`),
- ...(device.batteryPercentage ? [Widget.Label({
- className: 'txt-smallie',
- label: `${device.batteryPercentage}`,
- setup: (self) => {
- self.hook(device, (self) => {
- self.label = `${device.batteryPercentage}`;
- }, 'notify::batteryPercentage')
- }
- })] : []),
- ]
- });
- });
- self.visible = Bluetooth.connected_devices.length > 0;
- }, 'notify::connected-devices'),
-})
-
-const NetworkWiredIndicator = () => Widget.Stack({
- transition: 'slide_up_down',
- transitionDuration: userOptions.animations.durationSmall,
- children: {
- 'fallback': SimpleNetworkIndicator(),
- 'unknown': Widget.Label({ className: 'txt-norm icon-material', label: 'wifi_off' }),
- 'disconnected': Widget.Label({ className: 'txt-norm icon-material', label: 'signal_wifi_off' }),
- 'connected': Widget.Label({ className: 'txt-norm icon-material', label: 'lan' }),
- 'connecting': Widget.Label({ className: 'txt-norm icon-material', label: 'settings_ethernet' }),
- },
- setup: (self) => self.hook(Network, stack => {
- if (!Network.wired)
- return;
-
- const { internet } = Network.wired;
- if (['connecting', 'connected'].includes(internet))
- stack.shown = internet;
- else if (Network.connectivity !== 'full')
- stack.shown = 'disconnected';
- else
- stack.shown = 'fallback';
- }),
-});
-
-const SimpleNetworkIndicator = () => Widget.Icon({
- setup: (self) => self.hook(Network, self => {
- const icon = Network[Network.primary || 'wifi']?.iconName;
- self.icon = icon || '';
- self.visible = icon;
- }),
-});
-
-const NetworkWifiIndicator = () => Widget.Stack({
- transition: 'slide_up_down',
- transitionDuration: userOptions.animations.durationSmall,
- children: {
- 'disabled': Widget.Label({ className: 'txt-norm icon-material', label: 'signal_wifi_off' }),
- 'disconnected': Widget.Label({
- className: 'txt-norm icon-material',
- label: 'signal_wifi_statusbar_not_connected',
- }),
- 'connecting': Widget.Label({ className: 'txt-norm icon-material', label: 'settings_ethernet' }),
- '0': Widget.Label({ className: 'txt-norm icon-material', label: 'signal_wifi_0_bar' }),
- '1': Widget.Label({ className: 'txt-norm icon-material', label: 'network_wifi_1_bar' }),
- '2': Widget.Label({ className: 'txt-norm icon-material', label: 'network_wifi_2_bar' }),
- '3': Widget.Label({ className: 'txt-norm icon-material', label: 'network_wifi_3_bar' }),
- '4': Widget.Label({ className: 'txt-norm icon-material', label: 'signal_wifi_4_bar' }),
- },
- setup: (self) => self.hook(Network, (stack) => {
- if (!Network.wifi) {
- return;
- }
- if (!Network.wifi.enabled) {
- stack.shown = 'disabled';
- } else if (Network.wifi.internet == 'connected') {
- stack.shown = String(Math.ceil(Network.wifi.strength / 25));
- } else if (['disconnected', 'connecting'].includes(Network.wifi.internet)) {
- stack.shown = Network.wifi.internet;
- }
- }),
-});
-
-export const NetworkIndicator = () => Widget.Stack({
- transition: 'slide_up_down',
- transitionDuration: userOptions.animations.durationSmall,
- children: {
- 'fallback': SimpleNetworkIndicator(),
- 'wifi': NetworkWifiIndicator(),
- 'wired': NetworkWiredIndicator(),
- },
- setup: (self) => self.hook(Network, stack => {
- if (!Network.primary) {
- stack.shown = 'wifi';
- return;
- }
- const primary = Network.primary || 'fallback';
- if (['wifi', 'wired'].includes(primary))
- stack.shown = primary;
- else
- stack.shown = 'fallback';
- }),
-});
-
-const HyprlandXkbKeyboardLayout = async ({ useFlag } = {}) => {
- try {
- const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
- var languageStackArray = [];
-
- const updateCurrentKeyboards = () => {
- var initLangs = [];
- JSON.parse(Utils.exec('hyprctl -j devices')).keyboards
- .forEach(keyboard => {
- initLangs.push(...keyboard.layout.split(',').map(lang => lang.trim()));
- });
- initLangs = [...new Set(initLangs)];
- languageStackArray = Array.from({ length: initLangs.length }, (_, i) => {
- const lang = languages.find(lang => lang.layout == initLangs[i]);
- // if (!lang) return [
- // initLangs[i],
- // Widget.Label({ label: initLangs[i] })
- // ];
- // return [
- // lang.layout,
- // Widget.Label({ label: (useFlag ? lang.flag : lang.layout) })
- // ];
- // Object
- if (!lang) return {
- [initLangs[i]]: Widget.Label({ label: initLangs[i] })
- };
- return {
- [lang.layout]: Widget.Label({ label: (useFlag ? lang.flag : lang.layout) })
- };
- });
- };
- updateCurrentKeyboards();
- const widgetRevealer = Widget.Revealer({
- transition: 'slide_left',
- transitionDuration: userOptions.animations.durationSmall,
- revealChild: languageStackArray.length > 1,
- });
- const widgetKids = {
- ...languageStackArray.reduce((obj, lang) => {
- return { ...obj, ...lang };
- }, {}),
- 'undef': Widget.Label({ label: '?' }),
- }
- const widgetContent = Widget.Stack({
- transition: 'slide_up_down',
- transitionDuration: userOptions.animations.durationSmall,
- children: widgetKids,
- setup: (self) => self.hook(Hyprland, (stack, kbName, layoutName) => {
- if (!kbName) {
- return;
- }
- var lang = languages.find(lang => layoutName.includes(lang.name));
- if (lang) {
- widgetContent.shown = lang.layout;
- }
- else { // Attempt to support langs not listed
- lang = languageStackArray.find(lang => isLanguageMatch(lang[0], layoutName));
- if (!lang) stack.shown = 'undef';
- else stack.shown = lang[0];
- }
- }, 'keyboard-layout'),
- });
- widgetRevealer.child = widgetContent;
- return widgetRevealer;
- } catch {
- return null;
- }
-}
-
-const OptionalKeyboardLayout = async () => {
- try {
- return await HyprlandXkbKeyboardLayout({ useFlag: userOptions.appearance.keyboardUseFlag });
- } catch {
- return null;
- }
-};
-const createKeyboardLayoutInstances = async () => {
- const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
- const monitorsCount = Hyprland.monitors.length
- const instances = await Promise.all(
- Array.from({ length: monitorsCount }, () => OptionalKeyboardLayout())
- );
-
- return instances;
-};
-const optionalKeyboardLayoutInstances = await createKeyboardLayoutInstances()
-
-export const StatusIcons = (props = {}, monitor = 0) => Widget.Box({
- ...props,
- child: Widget.Box({
- className: 'spacing-h-15',
- children: [
- MicMuteIndicator(),
- optionalKeyboardLayoutInstances[monitor],
- NotificationIndicator(),
- NetworkIndicator(),
- Widget.Box({
- className: 'spacing-h-5',
- children: [BluetoothIndicator(), BluetoothDevices()]
- })
- ]
- })
-});
diff --git a/.config/ags/modules/.commonwidgets/statusicons_languages.js b/.config/ags/modules/.commonwidgets/statusicons_languages.js
deleted file mode 100644
index 560d9424e..000000000
--- a/.config/ags/modules/.commonwidgets/statusicons_languages.js
+++ /dev/null
@@ -1,62 +0,0 @@
-// For keyboard layout in statusicons.js
-// This list is not exhaustive. It just includes known/possible languages of users of my dotfiles
-// Add your language here if you use multi-lang xkb input. Else, ignore
-// Note that something like "French (Canada)" should go before "French"
-// and "English (US)" should go before "English"
-export const languages = [
- {
- layout: 'us',
- name: 'English (US)',
- flag: '🇺🇸'
- },
- {
- layout: 'ru',
- name: 'Russian',
- flag: '🇷🇺',
- },
- {
- layout: 'pl',
- name: 'Polish',
- flag: '🇷🇵🇵🇱',
- },
- {
- layout: 'ro',
- name: 'Romanian',
- flag: '🇷🇴',
- },
- {
- layout: 'ca',
- name: 'French (Canada)',
- flag: '🇫🇷',
- },
- {
- layout: 'fr',
- name: 'French',
- flag: '🇫🇷',
- },
- {
- layout: 'tr',
- name: 'Turkish',
- flag: '🇹🇷',
- },
- {
- layout: 'jp',
- name: 'Japanese',
- flag: '🇯🇵',
- },
- {
- layout: 'cn',
- name: 'Chinese',
- flag: '🇨🇳',
- },
- {
- layout: 'vn',
- name: 'Vietnamese',
- flag: '🇻🇳',
- },
- {
- layout: 'undef',
- name: 'Undefined',
- flag: '🧐',
- },
-]
\ No newline at end of file
diff --git a/.config/ags/modules/.commonwidgets/tabcontainer.js b/.config/ags/modules/.commonwidgets/tabcontainer.js
deleted file mode 100644
index 1e252f57e..000000000
--- a/.config/ags/modules/.commonwidgets/tabcontainer.js
+++ /dev/null
@@ -1,299 +0,0 @@
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-import Variable from 'resource:///com/github/Aylur/ags/variable.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-const { Box, Button, EventBox, Label, Overlay, Stack } = Widget;
-import { MaterialIcon } from './materialicon.js';
-import { NavigationIndicator } from './cairo_navigationindicator.js';
-import { setupCursorHover } from '../.widgetutils/cursorhover.js';
-import { DoubleRevealer } from '../.widgethacks/advancedrevealers.js';
-
-export const TabContainer = ({
- icons, names, children, initIndex = 0,
- className = '', setup = () => { },
- onChange = () => { },
- extraTabStripWidgets = [],
- ...rest
-}) => {
- const shownIndex = Variable(initIndex);
- let previousShownIndex = 0;
- const count = Math.min(icons.length, names.length, children.length);
- const tabs = Box({
- homogeneous: true,
- children: Array.from({ length: count }, (_, i) => Button({ // Tab button
- className: 'tab-btn',
- onClicked: () => shownIndex.value = i,
- setup: setupCursorHover,
- child: Box({
- hpack: 'center',
- vpack: 'center',
- className: 'spacing-h-5 txt-small',
- children: [
- MaterialIcon(icons[i], 'norm'),
- Label({
- label: names[i],
- })
- ]
- })
- })),
- setup: (self) => self.hook(shownIndex, (self) => {
- self.children[previousShownIndex].toggleClassName('tab-btn-active', false);
- self.children[shownIndex.value].toggleClassName('tab-btn-active', true);
- previousShownIndex = shownIndex.value;
- }),
- });
- const tabIndicatorLine = Box({
- vertical: true,
- homogeneous: true,
- setup: (self) => self.hook(shownIndex, (self) => {
- self.children[0].css = `font-size: ${shownIndex.value}px;`;
- }),
- children: [NavigationIndicator({
- className: 'tab-indicator',
- count: count,
- css: `font-size: ${shownIndex.value}px;`,
- })],
- });
- const tabSection = Box({
- homogeneous: true,
- children: [EventBox({
- onScrollUp: () => mainBox.prevTab(),
- onScrollDown: () => mainBox.nextTab(),
- child: Box({
- className: 'spacing-h-5',
- children: [
- Box({
- vertical: true,
- hexpand: true,
- children: [
- tabs,
- tabIndicatorLine
- ]
- }),
- ...extraTabStripWidgets,
- ]
- })
- })]
- });
-
- shownIndex.setValue(initIndex)
- const contentStack = Stack({
- transition: 'slide_left_right',
- children: children.reduce((acc, currentValue, index) => {
- acc[index] = currentValue;
- return acc;
- }, {}),
- setup: (self) => self.hook(shownIndex, (self) => {
- self.shown = `${shownIndex.value}`;
- }),
- });
-
- const mainBox = Box({
- attribute: {
- children: children,
- shown: shownIndex,
- names: names,
- },
- vertical: true,
- className: `spacing-v-5 ${className}`,
- setup: (self) => {
- self.pack_start(tabSection, false, false, 0);
- self.pack_end(contentStack, true, true, 0);
- setup(self);
- self.hook(shownIndex, (self) => onChange(self, shownIndex.value));
- },
- ...rest,
- });
-
- mainBox.nextTab = () => shownIndex.value = Math.min(shownIndex.value + 1, count - 1);
- mainBox.prevTab = () => shownIndex.value = Math.max(shownIndex.value - 1, 0);
- mainBox.cycleTab = () => shownIndex.value = (shownIndex.value + 1) % count;
-
- return mainBox;
-}
-
-
-export const IconTabContainer = ({
- iconWidgets, names, children, className = '',
- initIndex = 0,
- setup = () => { }, onChange = () => { },
- tabsHpack = 'center', tabSwitcherClassName = '',
- ...rest
-}) => {
- const shownIndex = Variable(initIndex);
- let previousShownIndex = 0;
- const count = Math.min(iconWidgets.length, names.length, children.length);
- const tabs = Box({
- hpack: tabsHpack,
- className: `spacing-h-5 ${tabSwitcherClassName}`,
- children: iconWidgets.map((icon, i) => Button({
- className: 'tab-icon',
- tooltipText: names[i],
- child: icon,
- setup: setupCursorHover,
- onClicked: () => shownIndex.value = i,
- })),
- setup: (self) => self.hook(shownIndex, (self) => {
- self.children[previousShownIndex].toggleClassName('tab-icon-active', false);
- self.children[shownIndex.value].toggleClassName('tab-icon-active', true);
- previousShownIndex = shownIndex.value;
- }),
- });
- const tabSection = Box({
- homogeneous: true,
- children: [EventBox({
- onScrollUp: () => mainBox.prevTab(),
- onScrollDown: () => mainBox.nextTab(),
- child: Box({
- vertical: true,
- hexpand: true,
- children: [
- tabs,
- ]
- })
- })]
- });
- const contentStack = Stack({
- transition: 'slide_left_right',
- children: children.reduce((acc, currentValue, index) => {
- acc[index] = currentValue;
- return acc;
- }, {}),
- setup: (self) => self.hook(shownIndex, (self) => {
- self.shown = `${shownIndex.value}`;
- }),
- });
- const mainBox = Box({
- attribute: {
- children: children,
- shown: shownIndex,
- names: names,
- },
- vertical: true,
- className: `spacing-v-5 ${className}`,
- setup: (self) => {
- self.pack_start(tabSection, false, false, 0);
- self.pack_end(contentStack, true, true, 0);
- setup(self);
- self.hook(shownIndex, (self) => onChange(self, shownIndex.value));
- },
- ...rest,
- });
- mainBox.nextTab = () => shownIndex.value = Math.min(shownIndex.value + 1, count - 1);
- mainBox.prevTab = () => shownIndex.value = Math.max(shownIndex.value - 1, 0);
- mainBox.cycleTab = () => shownIndex.value = (shownIndex.value + 1) % count;
- mainBox.shown = shownIndex;
-
- return mainBox;
-}
-
-export const ExpandingIconTabContainer = ({
- icons, names, children, className = '',
- setup = () => { }, onChange = () => { },
- tabsHpack = 'center', tabSwitcherClassName = '',
- transitionDuration = userOptions.animations.durationLarge,
- ...rest
-}) => {
- const shownIndex = Variable(0);
- let previousShownIndex = 0;
- const count = Math.min(icons.length, names.length, children.length);
- const tabs = Box({
- hpack: tabsHpack,
- className: `spacing-h-5 ${tabSwitcherClassName}`,
- children: icons.map((icon, i) => {
- const tabIcon = MaterialIcon(icon, 'norm', { hexpand: true });
- const tabName = DoubleRevealer({
- transition1: 'slide_right',
- transition2: 'crossfade',
- duration1: 0,
- duration2: 0,
- // duration1: userOptions.animations.durationSmall,
- // duration2: userOptions.animations.durationSmall,
- child: Label({
- className: 'margin-left-5 txt-small',
- label: names[i],
- }),
- revealChild: i === shownIndex.value,
- })
- const button = Button({
- className: 'tab-icon-expandable',
- tooltipText: names[i],
- child: Box({
- homogeneous: true,
- children: [Box({
- hpack: 'center',
- children: [
- tabIcon,
- tabName,
- ]
- })],
- }),
- setup: setupCursorHover,
- onClicked: () => shownIndex.value = i,
- });
- button.toggleFocus = (value) => {
- tabIcon.hexpand = !value;
- button.toggleClassName('tab-icon-expandable-active', value);
- tabName.toggleRevealChild(value);
- }
- return button;
- }),
- setup: (self) => self.hook(shownIndex, (self) => {
- self.children[previousShownIndex].toggleFocus(false);
- self.children[shownIndex.value].toggleFocus(true);
- previousShownIndex = shownIndex.value;
- }),
- });
- const tabSection = Box({
- homogeneous: true,
- children: [EventBox({
- onScrollUp: () => mainBox.prevTab(),
- onScrollDown: () => mainBox.nextTab(),
- child: Box({
- vertical: true,
- hexpand: true,
- children: [
- tabs,
- ]
- })
- })]
- });
- const contentStack = Stack({
- transition: 'slide_left_right',
- transitionDuration: transitionDuration,
- children: children.reduce((acc, currentValue, index) => {
- acc[index] = currentValue;
- return acc;
- }, {}),
- setup: (self) => self.hook(shownIndex, (self) => {
- self.shown = `${shownIndex.value}`;
- }),
- });
- const mainBox = Box({
- attribute: {
- children: children,
- shown: shownIndex,
- names: names,
- },
- vertical: true,
- className: `spacing-v-5 ${className}`,
- setup: (self) => {
- self.pack_start(tabSection, false, false, 0);
- self.pack_end(contentStack, true, true, 0);
- setup(self);
- self.hook(shownIndex, (self) => onChange(self, shownIndex.value));
- },
- ...rest,
- });
- mainBox.nextTab = () => shownIndex.value = Math.min(shownIndex.value + 1, count - 1);
- mainBox.prevTab = () => shownIndex.value = Math.max(shownIndex.value - 1, 0);
- mainBox.cycleTab = () => shownIndex.value = (shownIndex.value + 1) % count;
- mainBox.focusName = (name) => {
- const focusIndex = names.indexOf(name);
- if (focusIndex !== -1) {
- shownIndex.value = focusIndex;
- }
- }
- mainBox.shown = shownIndex;
-
- return mainBox;
-}
diff --git a/.config/ags/modules/.configuration/default_options.jsonc b/.config/ags/modules/.configuration/default_options.jsonc
deleted file mode 100644
index ef19f14e4..000000000
--- a/.config/ags/modules/.configuration/default_options.jsonc
+++ /dev/null
@@ -1,291 +0,0 @@
-// This file is parsed with a custom JSONC parser.
-// Don't expect every JSONC feature in... say, vscode, to work.
-{
- // General stuff
- "ai": {
- "defaultGPTProvider": "ollama_llama_3_2",
- "defaultTemperature": 0.5,
- "enhancements": true,
- "charsEachUpdate": 50, // Lower = smoother update rate, but more update lag
- "keep_alive": -1, // For ollama. -1 means forever
- "useHistory": false,
- "safety": true,
- "writingCursor": " ...", // Warning: Using weird characters can mess up Markdown rendering
- "proxyUrl": null, // Can be "socks5://127.0.0.1:9050" or "http://127.0.0.1:8080" for example. Leave it blank if you don't need it.
- "extraGptModels": {
- // Below is an example. Copy to user_options.jsonc and edit it
- // The base url is conveniently ollama's btw
- // "model_id": {
- // "name": "User-added model",
- // "logo_name": "ollama-symbolic",
- // "description": "A model added by the user",
- // "base_url": "http://localhost:11434/v1/chat/completions",
- // "key_get_url": "",
- // "requires_key": false,
- // "key_file": "api_key_file.txt",
- // "model": "model-name"
- // },
- }
- },
- "animations": {
- "choreographyDelay": 35,
- "durationSmall": 110,
- "durationLarge": 180
- },
- "appearance": {
- "autoDarkMode": { // Turns on dark mode in certain hours. Time in 24h format
- "enabled": false,
- "from": "18:10",
- "to": "6:10"
- },
- "borderless": false, // Uhm experimental...
- "keyboardUseFlag": false, // Use flag emoji instead of abbreviation letters
- "layerSmoke": false,
- "layerSmokeStrength": 0.2,
- "barRoundCorners": 1, // 0: No, 1: Yes
- "fakeScreenRounding": 2 // 0: None | 1: Always | 2: When not fullscreen
- },
- "apps": {
- "bluetooth": "blueberry",
- "imageViewer": "loupe",
- "network": "XDG_CURRENT_DESKTOP=\"gnome\" gnome-control-center wifi",
- "settings": "XDG_CURRENT_DESKTOP=\"gnome\" gnome-control-center",
- "taskManager": "gnome-usage",
- "terminal": "foot" // This is only for shell actions
- },
- "bar": {
- // Whether to show Swap and CPU usage when there's media. RAM is always shown.
- "alwaysShowFullResources": false,
- // Array of bar modes for each monitor. Hit Ctrl+Alt+Slash to cycle.
- // Modes: "normal", "focus" (workspace indicator only), "nothing"
- // Example for four monitors: ["normal", "focus", "normal", "nothing"]
- "modes": [
- "normal"
- ]
- },
- "battery": {
- "low": 20,
- "critical": 10,
- "warnLevels": [
- 20,
- 15,
- 5
- ],
- "warnTitles": [
- "Low battery",
- "Very low battery",
- "Critical Battery"
- ],
- "warnMessages": [
- "Plug in the charger",
- "You there?",
- "PLUG THE CHARGER ALREADY"
- ],
- "suspendThreshold": 3
- },
- "brightness": {
- // Object of controller names for each monitor, either "brightnessctl" or "ddcutil" or "auto"
- // "default" one will be used if unspecified
- // Examples
- // "eDP-1": "brightnessctl",
- // "DP-1": "ddcutil",
- "controllers": {
- "default": "auto"
- }
- },
- "cheatsheet": {
- "keybinds": {
- "configPath": "" // Path to hyprland keybind config file. Leave empty for default (~/.config/hypr/hyprland/keybinds.conf)
- }
- },
- "gaming": {
- "crosshair": {
- "size": 20,
- "color": "rgba(113,227,32,0.9)"
- }
- },
- "i18n": {
- "langCode": "", //Customize the locale, such as zh_CN,Optional value references "~/.config/ags/i18n/locales/"
- "extraLogs": false
- },
- "monitors": {
- "scaleMethod": "division" // Either "division" [default] or "gdk"
- },
- "music": {
- "preferredPlayer": "plasma-browser-integration"
- },
- "onScreenKeyboard": {
- "layout": "qwerty_full" // See modules/onscreenkeyboard/onscreenkeyboard.js for available layouts
- },
- "overview": {
- "scale": 0.18, // Relative to screen size
- "numOfRows": 2,
- "numOfCols": 5,
- "wsNumScale": 0.09,
- "wsNumMarginScale": 0.07
- },
- "sidebar": {
- "image": {
- "columns": 2,
- "batchCount": 20,
- "allowNsfw": false
- },
- "pages": {
- "order": [
- "apis",
- "tools"
- ],
- "defaultPage": "apis",
- "apis": {
- "order": [
- "gemini",
- "gpt",
- "waifu",
- "booru"
- ],
- "defaultPage": "gemini"
- }
- },
- "quickToggles": {
- "order": [
- "wifi",
- "bluetooth",
- "nightlight",
- "gamemode",
- "idleinhibitor",
- "cloudflarewarp"
- ]
- },
- "calendar": {
- "expandByDefault": true
- }
- },
- "search": {
- "enableFeatures": {
- "actions": true,
- "commands": true,
- "mathResults": true,
- "directorySearch": true,
- "aiSearch": true,
- "webSearch": true
- },
- "engineBaseUrl": "https://www.google.com/search?q=",
- "excludedSites": [
- "quora.com"
- ]
- },
- "time": {
- // See https://docs.gtk.org/glib/method.DateTime.format.html
- // Here's the 12h format: "%I:%M%P"
- // For seconds, add "%S" and set interval to 1000
- "format": "%H:%M",
- "interval": 5000,
- "dateFormatLong": "%A, %d/%m", // On bar
- "dateInterval": 5000,
- "dateFormat": "%d/%m", // On notif time
- "calendarDateFormat": "%d %B %Y"
- },
- "weather": {
- "city": "",
- "preferredUnit": "C" // Either C or F
- },
- "workspaces": {
- "shown": 10
- },
- "dock": {
- "enabled": false,
- "hiddenThickness": 5,
- "pinnedApps": [
- "firefox",
- "org.gnome.Nautilus"
- ],
- "ignoredAppsRegex": [],
- "layer": "top",
- "monitorExclusivity": true, // Dock will move to other monitor along with focus if enabled
- "searchPinnedAppIcons": false, // Try to search for the correct icon if the app class isn't an icon name
- "trigger": [
- "client-added",
- "client-removed"
- ], // client_added, client_move, workspace_active, client_active
- // Automatically hide dock after `interval` ms since trigger
- "autoHide": [
- {
- "trigger": "client-added",
- "interval": 500
- },
- {
- "trigger": "client-removed",
- "interval": 500
- }
- ]
- },
- // Longer stuff
- "icons": {
- // Find the window's icon by its class with levenshteinDistance
- // The file names are processed at startup, so if there
- // are too many files in the search path it'll affect performance
- // Example: ["/usr/share/icons/Tela-nord/scalable/apps"]
- "searchPaths": [
- ""
- ],
- "symbolicIconTheme": {
- "dark": "Adwaita",
- "light": "Adwaita"
- },
- "substitutions": {
- "code-url-handler": "visual-studio-code",
- "Code": "visual-studio-code",
- "GitHub Desktop": "github-desktop",
- "Minecraft* 1.20.1": "minecraft",
- "gnome-tweaks": "org.gnome.tweaks",
- "pavucontrol-qt": "pavucontrol",
- "wps": "wps-office2019-kprometheus",
- "wpsoffice": "wps-office2019-kprometheus",
- "footclient": "foot",
- "zen": "zen-browser",
- "": "image-missing"
- },
- "regexSubstitutions": [
- {
- "regex": "/^steam_app_(\\d+)$/",
- "replace": "steam_icon_$1"
- }
- ]
- },
- "keybinds": {
- // Format: "Modifier_1+...+Modifier_n+key". The key is CaSe SeNsItIvE!
- // Modifiers: Shift Ctrl Alt Hyper Meta
- // See https://docs.gtk.org/gdk3/index.html#constants for keys (listed as KEY_key)
- // You can assign multiple keybinds for the same action. Just split them with a comma
- // Example: "Ctrl+Page_Down, ctrl+Tab"
- "overview": {
- "altMoveLeft": "Ctrl+B",
- "altMoveRight": "Ctrl+F",
- "deleteToEnd": "Ctrl+K"
- },
- "sidebar": {
- "apis": {
- "nextTab": "Page_Down",
- "prevTab": "Page_Up"
- },
- "options": { // Right sidebar
- "nextTab": "Page_Down",
- "prevTab": "Page_Up"
- },
- "expand": "Ctrl+E",
- "pin": "Ctrl+P",
- "cycleTab": "Ctrl+Tab",
- "nextTab": "Ctrl+Page_Down",
- "prevTab": "Ctrl+Page_Up"
- },
- "cheatsheet": {
- "keybinds": {
- "nextTab": "Page_Down",
- "prevTab": "Page_Up"
- },
- "nextTab": "Ctrl+Page_Down",
- "prevTab": "Ctrl+Page_Up",
- "cycleTab": "Ctrl+Tab"
- }
- }
-}
\ No newline at end of file
diff --git a/.config/ags/modules/.configuration/user_options.js b/.config/ags/modules/.configuration/user_options.js
deleted file mode 100644
index 878070b66..000000000
--- a/.config/ags/modules/.configuration/user_options.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'
-import { parseJSONC } from '../.miscutils/jsonc.js';
-
-function overrideConfigRecursive(userOverrides, configOptions = {}) {
- for (const [key, value] of Object.entries(userOverrides)) {
- if (typeof value === 'object'
- && !(value instanceof Array)
- && configOptions[key]) {
- overrideConfigRecursive(value, configOptions[key]);
- }
- else {
- configOptions[key] = value;
- }
- }
-}
-
-// Load default options from ~/.config/ags/modules/.configuration/default_options.jsonc
-const defaultConfigFile = `${App.configDir}/modules/.configuration/default_options.jsonc`;
-const defaultConfigFileContents = Utils.readFile(defaultConfigFile);
-const defaultConfigOptions = parseJSONC(defaultConfigFileContents);
-
-// Clone the default config to avoid modifying the original
-let configOptions = JSON.parse(JSON.stringify(defaultConfigOptions));
-
-// Load user overrides
-const userOverrideFile = `${App.configDir}/user_options.jsonc`;
-const userOverrideContents = Utils.readFile(userOverrideFile);
-const userOverrides = parseJSONC(userOverrideContents);
-
-// Override defaults with user's options
-overrideConfigRecursive(userOverrides, configOptions);
-
-globalThis['userOptionsDefaults'] = defaultConfigOptions;
-globalThis['userOptions'] = configOptions;
-export default configOptions;
diff --git a/.config/ags/modules/.miscutils/files.js b/.config/ags/modules/.miscutils/files.js
deleted file mode 100644
index 00c17b916..000000000
--- a/.config/ags/modules/.miscutils/files.js
+++ /dev/null
@@ -1,14 +0,0 @@
-const { Gio, GLib, Gtk } = imports.gi;
-
-export function fileExists(filePath) {
- let file = Gio.File.new_for_path(filePath);
- return file.query_exists(null);
-}
-
-export function expandTilde(path) {
- if (path.startsWith('~')) {
- return GLib.get_home_dir() + path.slice(1);
- } else {
- return path;
- }
-}
\ No newline at end of file
diff --git a/.config/ags/modules/.miscutils/icons.js b/.config/ags/modules/.miscutils/icons.js
deleted file mode 100644
index 66c09eda7..000000000
--- a/.config/ags/modules/.miscutils/icons.js
+++ /dev/null
@@ -1,28 +0,0 @@
-const { Gtk } = imports.gi;
-
-export function iconExists(iconName) {
- let iconTheme = Gtk.IconTheme.get_default();
- return iconTheme.has_icon(iconName);
-}
-
-export function substitute(str) {
- // Normal substitutions
- if (userOptions.icons.substitutions[str])
- return userOptions.icons.substitutions[str];
-
- // Regex substitutions
- for (let i = 0; i < userOptions.icons.regexSubstitutions.length; i++) {
- const substitution = userOptions.icons.regexSubstitutions[i];
- const replacedName = str.replace(
- substitution.regex,
- substitution.replace,
- );
- if (replacedName != str) return replacedName;
- }
-
- // Guess: convert to kebab case
- if (!iconExists(str)) str = str.toLowerCase().replace(/\s+/g, "-");
-
- // Original string
- return str;
-}
diff --git a/.config/ags/modules/.miscutils/jsonc.js b/.config/ags/modules/.miscutils/jsonc.js
deleted file mode 100644
index 689332880..000000000
--- a/.config/ags/modules/.miscutils/jsonc.js
+++ /dev/null
@@ -1,58 +0,0 @@
-export function parseJSONC(jsoncString) {
- let result = "";
- let inString = false;
- let inSingleQuote = false;
- let inMultiLineComment = false;
- let inSingleLineComment = false;
-
- for (let i = 0; i < jsoncString.length; i++) {
- let char = jsoncString[i];
- let nextChar = jsoncString[i + 1];
-
- // Handle string start/end
- if (!inSingleLineComment && !inMultiLineComment) {
- if (char === '"' && !inSingleQuote) {
- inString = !inString;
- } else if (char === "'" && !inString) {
- inSingleQuote = !inSingleQuote;
- }
- }
-
- // Handle single-line comments //
- if (!inString && !inSingleQuote && !inMultiLineComment && char === '/' && nextChar === '/') {
- inSingleLineComment = true;
- i++; // Skip next '/'
- continue;
- }
-
- // Handle multi-line comments /*
- if (!inString && !inSingleQuote && !inSingleLineComment && char === '/' && nextChar === '*') {
- inMultiLineComment = true;
- i++; // Skip next '*'
- continue;
- }
-
- // End single-line comment at newline
- if (inSingleLineComment && (char === '\n' || char === '\r')) {
- inSingleLineComment = false;
- }
-
- // End multi-line comment */
- if (inMultiLineComment && char === '*' && nextChar === '/') {
- inMultiLineComment = false;
- i++; // Skip next '/'
- continue;
- }
-
- // Only append characters if not inside a comment
- if (!inSingleLineComment && !inMultiLineComment) {
- result += char;
- }
- }
-
- // Remove trailing commas from objects and arrays
- result = result.replace(/,\s*([\]}])/g, '$1');
-
- // Parse as JSON
- return JSON.parse(result);
-}
diff --git a/.config/ags/modules/.miscutils/mathfuncs.js b/.config/ags/modules/.miscutils/mathfuncs.js
deleted file mode 100644
index 7a7c1da61..000000000
--- a/.config/ags/modules/.miscutils/mathfuncs.js
+++ /dev/null
@@ -1,16 +0,0 @@
-
-export function clamp(x, min, max) {
- return Math.min(Math.max(x, min), max);
-}
-
-export function truncateToPrecision(value, precision) {
- const factor = Math.pow(10, precision);
- const result = Math.round(value * factor) / factor;
- return result;
-}
-
-export function distance(x1, y1, x2, y2) {
- const distanceX = Math.abs(x1 - x2);
- const distanceY = Math.abs(y1 - y2);
- return Math.sqrt(distanceX * distanceX + distanceY * distanceY)
-}
\ No newline at end of file
diff --git a/.config/ags/modules/.miscutils/md2pango.js b/.config/ags/modules/.miscutils/md2pango.js
deleted file mode 100644
index e619cf972..000000000
--- a/.config/ags/modules/.miscutils/md2pango.js
+++ /dev/null
@@ -1,98 +0,0 @@
-// Converts from Markdown to Pango. This does not support code blocks.
-// For illogical-impulse, code blocks are treated separately, in their own GtkSourceView widgets.
-// Partly inherited from https://github.com/ubunatic/md2pango
-
-const monospaceFonts = 'JetBrains Mono NF, JetBrains Mono Nerd Font, JetBrains Mono NL, SpaceMono NF, SpaceMono Nerd Font, monospace';
-
-const codeBlockRegex = /^\s*```([a-zA-Z0-9]+)?\n?/;
-const replacements = {
- 'indents': [
- { name: 'BULLET', re: /^(\s*)([\*\-]\s)(.*)(\s*)$/, sub: ' $1- $3' },
- { name: 'NUMBERING', re: /^(\s*[0-9]+\.\s)(.*)(\s*)$/, sub: ' $1 $2' },
- ],
- 'escapes': [
- { name: 'COMMENT', re: //, sub: '' },
- { name: 'AMPERSTAND', re: /&/g, sub: '&' },
- { name: 'LESSTHAN', re: //g, sub: '>' },
- ],
- 'sections': [
- { name: 'H1', re: /^(#\s+)(.*)(\s*)$/, sub: '$2' },
- { name: 'H2', re: /^(##\s+)(.*)(\s*)$/, sub: '$2' },
- { name: 'H3', re: /^(###\s+)(.*)(\s*)$/, sub: '$2' },
- { name: 'H4', re: /^(####\s+)(.*)(\s*)$/, sub: '$2' },
- { name: 'H5', re: /^(#####\s+)(.*)(\s*)$/, sub: '$2' },
- ],
- 'styles': [
- { name: 'BOLD', re: /(\*\*)(\S[\s\S]*?\S)(\*\*)/g, sub: "$2" },
- { name: 'UND', re: /(__)(\S[\s\S]*?\S)(__)/g, sub: "$2" },
- { name: 'EMPH', re: /\*(\S.*?\S)\*/g, sub: "$1" },
- // { name: 'EMPH', re: /_(\S.*?\S)_/g, sub: "$1" },
- { name: 'HEXCOLOR', re: /#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})/g, sub: '#$1' },
- { name: 'INLCODE', re: /(`)([^`]*)(`)/g, sub: '$2' },
- // { name: 'UND', re: /(__|\*\*)(\S[\s\S]*?\S)(__|\*\*)/g, sub: "$2" },
- ],
- 'forceLatex': [
- { name: 'LATEX_INLINE_SQUARE', re: /\\\[(.*?)\\\]/g, sub: '\n```latex\n$1\n```' },
- { name: 'LATEX_INLINE_ROUND', re: /\\\((.*?)\\\)/g, sub: '\n```latex\n$1\n```' },
- { name: 'LATEX_INLINE_DOLLAR', re: /\$(.*?)\$/g, sub: '\n```latex\n$1\n```' }
- ]
-}
-
-const replaceCategory = (text, replaces) => {
- for (const type of replaces) {
- text = text.replace(type.re, type.sub);
- }
- return text;
-}
-
-// Main function
-
-export function replaceInlineLatexWithCodeBlocks(text) {
- return text.replace(/\\\[(.*?)\\\]|\\\((.*?)\\\)|\$\$(.*?)\$\$|(?:^|[^\w])\$(.*?[^\\])\$(?!\w)/gs, (match, square, round, double, single) => {
- const latex = square || round || double || single;
- return `\n\`\`\`latex\n${latex}\n\`\`\`\n`;
- });
-}
-
-export default (text) => {
- let lines = text.split('\n')
- let output = [];
- let inCode = false;
- // Replace
- for (const line of lines) {
- let result = line;
- if (codeBlockRegex.test(line)) inCode = !inCode;
- if (inCode) continue;
- result = replaceCategory(result, replacements.indents);
- result = replaceCategory(result, replacements.escapes);
- result = replaceCategory(result, replacements.sections);
- result = replaceCategory(result, replacements.styles);
- output.push(result)
- }
- // Remove trailing whitespaces
- output = output.map(line => line.replace(/ +$/, ''))
- return output.join('\n');
-}
-
-export const markdownTest = `## Inline formatting
-- **Bold** *Italics* __Underline__
-- \`Monospace text\` 🤓
-- Colors
- - Nvidia green #7ABB08
- - Soundcloud orange #FF5500
-## Code block
-\`\`\`cpp
-#include
-const std::string GREETING = "UwU";
-int main(int argc, char* argv[]) {
- std::cout << GREETING;
-}
-\`\`\`
-## LaTeX
-- Inline LaTeX: \\[ \\frac{d}{dx} \\left( \\frac{x-438}{x^2+23x-7} \\right) = \\frac{-x^2 + 869}{(x^2+23x-7)^2} \\]
-- Block LaTeX:
-\`\`\`latex
-\\frac{d}{dx} \\left( \\frac{x-438}{x^2+23x-7} \\right) = \\frac{-x^2 + 869}{(x^2+23x-7)^2} \\\\ → \\\\ cos(2x) = 2cos^2(x) - 1 = 1 - 2sin^2(x) = cos^2(x) - sin^2(x)
-\`\`\`
-`;
diff --git a/.config/ags/modules/.miscutils/objects.js b/.config/ags/modules/.miscutils/objects.js
deleted file mode 100644
index 90ac62a22..000000000
--- a/.config/ags/modules/.miscutils/objects.js
+++ /dev/null
@@ -1,33 +0,0 @@
-export function getNestedProperty(obj, path) {
- return path.split('.').reduce((current, key) => {
- return (current && typeof current === 'object' && current.hasOwnProperty(key)) ? current[key] : undefined;
- }, obj);
-}
-
-export function updateNestedProperty(obj, path, newValue) {
- const pathArray = path.split('.');
- const lastKeyIndex = pathArray.length - 1;
-
- let current = obj;
-
- for (let i = 0; i < lastKeyIndex; i++) {
- const key = pathArray[i];
- if (!current || typeof current !== 'object') {
- return false; // Previous part of path is not an object
- }
-
- if (!current.hasOwnProperty(key)) {
- current[key] = {}; // Create the missing object
- }
- current = current[key];
- }
-
- const lastKey = pathArray[lastKeyIndex];
-
- if (!current || typeof current !== 'object') {
- return false; // Parent is not an object
- }
-
- current[lastKey] = newValue;
- return true;
-}
diff --git a/.config/ags/modules/.miscutils/system.js b/.config/ags/modules/.miscutils/system.js
deleted file mode 100644
index 377463b29..000000000
--- a/.config/ags/modules/.miscutils/system.js
+++ /dev/null
@@ -1,61 +0,0 @@
-const { GLib } = imports.gi;
-import Variable from 'resource:///com/github/Aylur/ags/variable.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { execAsync, exec } = Utils;
-
-export const distroID = exec(`bash -c 'cat /etc/os-release | grep "^ID=" | cut -d "=" -f 2 | sed "s/\\"//g"'`).trim();
-export const isDebianDistro = (distroID == 'linuxmint' || distroID == 'ubuntu' || distroID == 'debian' || distroID == 'zorin' || distroID == 'popos' || distroID == 'raspbian' || distroID == 'kali');
-export const isArchDistro = (distroID == 'arch' || distroID == 'endeavouros' || distroID == 'cachyos');
-export const hasFlatpak = !!exec(`bash -c 'command -v flatpak'`);
-
-const LIGHTDARK_FILE_LOCATION = `${GLib.get_user_state_dir()}/ags/user/colormode.txt`;
-export const darkMode = Variable(!(Utils.readFile(LIGHTDARK_FILE_LOCATION).split('\n')[0].trim() == 'light'));
-darkMode.connect('changed', ({ value }) => {
- let lightdark = value ? "dark" : "light";
- execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_state_dir()}/ags/user && sed -i "1s/.*/${lightdark}/" ${GLib.get_user_state_dir()}/ags/user/colormode.txt`])
- .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchcolor.sh`]))
- .then(execAsync(['bash', '-c', `command -v darkman && darkman set ${lightdark}`])) // Optional darkman integration
- .catch(print);
-});
-globalThis['darkMode'] = darkMode;
-export const hasPlasmaIntegration = !!Utils.exec('bash -c "command -v plasma-browser-integration-host"');
-
-export const getDistroIcon = () => {
- // Arches
- if(distroID == 'arch') return 'arch-symbolic';
- if(distroID == 'endeavouros') return 'endeavouros-symbolic';
- if(distroID == 'cachyos') return 'cachyos-symbolic';
- // Funny flake
- if(distroID == 'nixos') return 'nixos-symbolic';
- // Cool thing
- if(distroID == 'fedora') return 'fedora-symbolic';
- // Debians
- if(distroID == 'linuxmint') return 'ubuntu-symbolic';
- if(distroID == 'ubuntu') return 'ubuntu-symbolic';
- if(distroID == 'debian') return 'debian-symbolic';
- if(distroID == 'zorin') return 'ubuntu-symbolic';
- if(distroID == 'popos') return 'ubuntu-symbolic';
- if(distroID == 'raspbian') return 'debian-symbolic';
- if(distroID == 'kali') return 'debian-symbolic';
- return 'linux-symbolic';
-}
-
-export const getDistroName = () => {
- // Arches
- if(distroID == 'arch') return 'Arch Linux';
- if(distroID == 'endeavouros') return 'EndeavourOS';
- if(distroID == 'cachyos') return 'CachyOS';
- // Funny flake
- if(distroID == 'nixos') return 'NixOS';
- // Cool thing
- if(distroID == 'fedora') return 'Fedora';
- // Debians
- if(distroID == 'linuxmint') return 'Linux Mint';
- if(distroID == 'ubuntu') return 'Ubuntu';
- if(distroID == 'debian') return 'Debian';
- if(distroID == 'zorin') return 'Zorin';
- if(distroID == 'popos') return 'Pop!_OS';
- if(distroID == 'raspbian') return 'Raspbian';
- if(distroID == 'kali') return 'Kali Linux';
- return 'Linux';
-}
diff --git a/.config/ags/modules/.widgethacks/advancedrevealers.js b/.config/ags/modules/.widgethacks/advancedrevealers.js
deleted file mode 100644
index 3f1279314..000000000
--- a/.config/ags/modules/.widgethacks/advancedrevealers.js
+++ /dev/null
@@ -1,86 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-
-const { Revealer, Scrollable } = Widget;
-
-export const MarginRevealer = ({
- transition = 'slide_down',
- child,
- revealChild,
- showClass = 'element-show', // These are for animation curve, they don't really hide
- hideClass = 'element-hide', // Don't put margins in these classes!
- extraSetup = () => { },
- ...rest
-}) => {
- const widget = Scrollable({
- ...rest,
- attribute: {
- 'revealChild': true, // It'll be set to false after init if it's supposed to hide
- 'transition': transition,
- 'show': () => {
- if (widget.attribute.revealChild) return;
- widget.hscroll = 'never';
- widget.vscroll = 'never';
- child.toggleClassName(hideClass, false);
- child.toggleClassName(showClass, true);
- widget.attribute.revealChild = true;
- child.css = 'margin: 0px;';
- },
- 'hide': () => {
- if (!widget.attribute.revealChild) return;
- child.toggleClassName(hideClass, true);
- child.toggleClassName(showClass, false);
- widget.attribute.revealChild = false;
- if (widget.attribute.transition == 'slide_left')
- child.css = `margin-right: -${child.get_allocated_width()}px;`;
- else if (widget.attribute.transition == 'slide_right')
- child.css = `margin-left: -${child.get_allocated_width()}px;`;
- else if (widget.attribute.transition == 'slide_up')
- child.css = `margin-bottom: -${child.get_allocated_height()}px;`;
- else if (widget.attribute.transition == 'slide_down')
- child.css = `margin-top: -${child.get_allocated_height()}px;`;
- },
- 'toggle': () => {
- if (widget.attribute.revealChild) widget.attribute.hide();
- else widget.attribute.show();
- },
- },
- child: child,
- hscroll: `${revealChild ? 'never' : 'always'}`,
- vscroll: `${revealChild ? 'never' : 'always'}`,
- setup: (self) => {
- extraSetup(self);
- }
- });
- child.toggleClassName(`${revealChild ? showClass : hideClass}`, true);
- return widget;
-}
-
-// TODO: Allow reveal update. Currently this just helps at declaration
-export const DoubleRevealer = ({
- transition1 = 'slide_right',
- transition2 = 'slide_left',
- duration1 = 150,
- duration2 = 150,
- child,
- revealChild,
- ...rest
-}) => {
- const r2 = Revealer({
- transition: transition2,
- transitionDuration: duration2,
- revealChild: revealChild,
- child: child,
- });
- const r1 = Revealer({
- transition: transition1,
- transitionDuration: duration1,
- revealChild: revealChild,
- child: r2,
- ...rest,
- })
- r1.toggleRevealChild = (value) => {
- r1.revealChild = value;
- r2.revealChild = value;
- }
- return r1;
-}
diff --git a/.config/ags/modules/.widgethacks/popupwindow.js b/.config/ags/modules/.widgethacks/popupwindow.js
deleted file mode 100644
index e0e101199..000000000
--- a/.config/ags/modules/.widgethacks/popupwindow.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-const { Box, Window } = Widget;
-
-
-export default ({
- name,
- child,
- showClassName = "",
- hideClassName = "",
- ...props
-}) => {
- return Window({
- name,
- visible: false,
- layer: 'top',
- ...props,
-
- child: Box({
- setup: (self) => {
- self.keybind("Escape", () => closeEverything());
- if (showClassName != "" && hideClassName !== "") {
- self.hook(App, (self, currentName, visible) => {
- if (currentName === name) {
- self.toggleClassName(hideClassName, !visible);
- }
- });
-
- if (showClassName !== "" && hideClassName !== "")
- self.className = `${showClassName} ${hideClassName}`;
- }
- },
- child: child,
- }),
- });
-}
\ No newline at end of file
diff --git a/.config/ags/modules/.widgetutils/clickthrough.js b/.config/ags/modules/.widgetutils/clickthrough.js
deleted file mode 100644
index 505f1412d..000000000
--- a/.config/ags/modules/.widgetutils/clickthrough.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import Cairo from 'gi://cairo?version=1.0';
-
-export const dummyRegion = new Cairo.Region();
-export const enableClickthrough = (self) => self.input_shape_combine_region(dummyRegion);
\ No newline at end of file
diff --git a/.config/ags/modules/.widgetutils/cursorhover.js b/.config/ags/modules/.widgetutils/cursorhover.js
deleted file mode 100644
index 8633590ff..000000000
--- a/.config/ags/modules/.widgetutils/cursorhover.js
+++ /dev/null
@@ -1,36 +0,0 @@
-// Cursor names reference: https://docs.gtk.org/gdk4/ctor.Cursor.new_from_name.html
-const { Gdk } = imports.gi;
-
-export function setupCursorHover(button, cursorName = 'pointer') { // Hand pointing cursor on hover
- const display = Gdk.Display.get_default();
- button.connect('enter-notify-event', () => {
- const cursor = Gdk.Cursor.new_from_name(display, cursorName);
- button.get_window().set_cursor(cursor);
- });
-
- button.connect('leave-notify-event', () => {
- const cursor = Gdk.Cursor.new_from_name(display, 'default');
- button.get_window().set_cursor(cursor);
- });
-
-}
-
-export function setupCursorHoverAim(button) { // Crosshair cursor on hover
- setupCursorHover(button, 'crosshair');
-}
-
-export function setupCursorHoverGrab(button) { // Hand ready to grab on hover
- setupCursorHover(button, 'grab');
-}
-
-export function setupCursorHoverInfo(button) { // "?" mark cursor on hover
- setupCursorHover(button, 'help');
-}
-
-export function setupCursorHoverHResize(button) { // Resize left right
- setupCursorHover(button, 'ew-resize');
-}
-
-export function setupCursorHoverVResize(button) { // Resize up down
- setupCursorHover(button, 'ns-resize');
-}
diff --git a/.config/ags/modules/.widgetutils/keybind.js b/.config/ags/modules/.widgetutils/keybind.js
deleted file mode 100644
index 188ebc924..000000000
--- a/.config/ags/modules/.widgetutils/keybind.js
+++ /dev/null
@@ -1,34 +0,0 @@
-const { Gdk } = imports.gi;
-
-const MODS = {
- 'shift': Gdk.ModifierType.SHIFT_MASK,
- 'ctrl': Gdk.ModifierType.CONTROL_MASK,
- 'alt': Gdk.ModifierType.ALT_MASK,
- 'hyper': Gdk.ModifierType.HYPER_MASK,
- 'meta': Gdk.ModifierType.META_MASK
-}
-
-const checkSingleKeybind = (event, keybind) => {
- const pressedModMask = event.get_state()[1];
- const pressedKey = event.get_keyval()[1];
- const keys = keybind.split('+');
- for (let i = 0; i < keys.length; i++) {
- if (keys[i].toLowerCase() in MODS) {
- if (!(pressedModMask & MODS[keys[i].toLowerCase()])) {
- return false;
- }
- } else if (pressedKey !== Gdk[`KEY_${keys[i]}`] && pressedKey !== Gdk[`KEY_${keys[i].toLowerCase()}`]) {
- return false;
- }
- }
- return true;
-}
-
-export const checkKeybind = (event, keybind) => {
- const keybinds = keybind.replace(' ', '').split(',');
- for (let i = 0; i < keybinds.length; i++) {
- if (checkSingleKeybind(event, keybinds[i])) {
- return true;
- }
- }
-}
diff --git a/.config/ags/modules/bar/focus/workspaces_hyprland.js b/.config/ags/modules/bar/focus/workspaces_hyprland.js
deleted file mode 100644
index b5a101aa6..000000000
--- a/.config/ags/modules/bar/focus/workspaces_hyprland.js
+++ /dev/null
@@ -1,213 +0,0 @@
-const { GLib, Gdk, Gtk } = imports.gi;
-const Lang = imports.lang;
-const Cairo = imports.cairo;
-const Pango = imports.gi.Pango;
-const PangoCairo = imports.gi.PangoCairo;
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-const { Box, DrawingArea, EventBox } = Widget;
-import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
-
-const dummyWs = Box({ className: 'bar-ws-focus' }); // Not shown. Only for getting size props
-const dummyActiveWs = Box({ className: 'bar-ws-focus bar-ws-focus-active' }); // Not shown. Only for getting size props
-const dummyOccupiedWs = Box({ className: 'bar-ws-focus bar-ws-focus-occupied' }); // Not shown. Only for getting size props
-
-const WS_TAKEN_WIDTH_MULTIPLIER = 1.4;
-const floor = Math.floor;
-const ceil = Math.ceil;
-
-// Font size = workspace id
-const WorkspaceContents = (count = 10) => {
- return DrawingArea({
- className: 'menu-decel',
- attribute: {
- lastImmediateActiveWs: 0,
- immediateActiveWs: 0,
- initialized: false,
- workspaceMask: 0,
- workspaceGroup: 0,
- updateMask: (self) => {
- const offset = Math.floor((Hyprland.active.workspace.id - 1) / count) * userOptions.workspaces.shown;
- // if (self.attribute.initialized) return; // We only need this to run once
- const workspaces = Hyprland.workspaces;
- let workspaceMask = 0;
- for (let i = 0; i < workspaces.length; i++) {
- const ws = workspaces[i];
- if (ws.id <= offset || ws.id > offset + count) continue; // Out of range, ignore
- if (workspaces[i].windows > 0)
- workspaceMask |= (1 << (ws.id - offset));
- }
- // console.log('Mask:', workspaceMask.toString(2));
- self.attribute.workspaceMask = workspaceMask;
- // self.attribute.initialized = true;
- self.queue_draw();
- },
- toggleMask: (self, occupied, name) => {
- if (occupied) self.attribute.workspaceMask |= (1 << parseInt(name));
- else self.attribute.workspaceMask &= ~(1 << parseInt(name));
- self.queue_draw();
- },
- },
- setup: (area) => area
- .hook(Hyprland.active.workspace, (self) => {
- const newActiveWs = (Hyprland.active.workspace.id - 1) % count + 1;
- self.setCss(`font-size: ${newActiveWs}px;`);
- self.attribute.lastImmediateActiveWs = self.attribute.immediateActiveWs;
- self.attribute.immediateActiveWs = newActiveWs;
- const previousGroup = self.attribute.workspaceGroup;
- const currentGroup = Math.floor((Hyprland.active.workspace.id - 1) / count);
- if (currentGroup !== previousGroup) {
- self.attribute.updateMask(self);
- self.attribute.workspaceGroup = currentGroup;
- }
- })
- .hook(Hyprland, (self) => self.attribute.updateMask(self), 'notify::workspaces')
- .on('draw', Lang.bind(area, (area, cr) => {
- const offset = Math.floor((Hyprland.active.workspace.id - 1) / count) * userOptions.workspaces.shown;
-
- const allocation = area.get_allocation();
- const { width, height } = allocation;
-
- const workspaceStyleContext = dummyWs.get_style_context();
- const workspaceDiameter = workspaceStyleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
- const workspaceRadius = workspaceDiameter / 2;
- const wsbg = workspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
-
- const occupiedWorkspaceStyleContext = dummyOccupiedWs.get_style_context();
- const occupiedbg = occupiedWorkspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
-
- const activeWorkspaceStyleContext = dummyActiveWs.get_style_context();
- const activeWorkspaceWidth = activeWorkspaceStyleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
- // const activeWorkspaceWidth = 100;
- const activebg = activeWorkspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
-
- const widgetStyleContext = area.get_style_context();
- const activeWs = widgetStyleContext.get_property('font-size', Gtk.StateFlags.NORMAL);
- const lastImmediateActiveWs = area.attribute.lastImmediateActiveWs;
- const immediateActiveWs = area.attribute.immediateActiveWs;
-
- // Draw
- area.set_size_request(workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER * (count - 1) + activeWorkspaceWidth, -1);
- for (let i = 1; i <= count; i++) {
- if (i == immediateActiveWs) continue;
- let colors = {};
- if (area.attribute.workspaceMask & (1 << i)) colors = occupiedbg;
- else colors = wsbg;
-
- // if ((i == immediateActiveWs + 1 && immediateActiveWs < activeWs) ||
- // (i == immediateActiveWs + 1 && immediateActiveWs < activeWs)) {
- // const widthPercentage = (i == immediateActiveWs - 1) ?
- // 1 - (immediateActiveWs - activeWs) :
- // activeWs - immediateActiveWs;
- // cr.setSourceRGBA(colors.red * widthPercentage + activebg.red * (1 - widthPercentage),
- // colors.green * widthPercentage + activebg.green * (1 - widthPercentage),
- // colors.blue * widthPercentage + activebg.blue * (1 - widthPercentage),
- // colors.alpha);
- // }
- // else
- cr.setSourceRGBA(colors.red, colors.green, colors.blue, colors.alpha)
-
- const centerX = (i <= activeWs) ?
- (-workspaceRadius + (workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER * i))
- : -workspaceRadius + workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER * (count - 1) + activeWorkspaceWidth - ((count - i) * workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER);
- cr.arc(centerX, height / 2, workspaceRadius, 0, 2 * Math.PI);
- cr.fill();
- // What if shrinking
- if (i == floor(activeWs) && immediateActiveWs > activeWs) { // To right
- const widthPercentage = 1 - (ceil(activeWs) - activeWs);
- const leftX = centerX;
- const wsWidth = (activeWorkspaceWidth - (workspaceDiameter * 1.5)) * (1 - widthPercentage);
- cr.rectangle(leftX, height / 2 - workspaceRadius, wsWidth, workspaceDiameter);
- cr.fill();
- cr.arc(leftX + wsWidth, height / 2, workspaceRadius, 0, Math.PI * 2);
- cr.fill();
- }
- else if (i == ceil(activeWs) && immediateActiveWs < activeWs) { // To left
- const widthPercentage = activeWs - floor(activeWs);
- const rightX = centerX;
- const wsWidth = (activeWorkspaceWidth - (workspaceDiameter * 1.5)) * widthPercentage;
- const leftX = rightX - wsWidth;
- cr.rectangle(leftX, height / 2 - workspaceRadius, wsWidth, workspaceDiameter);
- cr.fill();
- cr.arc(leftX, height / 2, workspaceRadius, 0, Math.PI * 2);
- cr.fill();
- }
- }
-
- let widthPercentage, leftX, rightX, activeWsWidth;
- cr.setSourceRGBA(activebg.red, activebg.green, activebg.blue, activebg.alpha);
- if (immediateActiveWs > activeWs) { // To right
- const immediateActiveWs = ceil(activeWs);
- widthPercentage = immediateActiveWs - activeWs;
- rightX = -workspaceRadius + workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER * (count - 1) + activeWorkspaceWidth - ((count - immediateActiveWs) * workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER);
- activeWsWidth = (activeWorkspaceWidth - (workspaceDiameter * 1.5)) * (1 - widthPercentage);
- leftX = rightX - activeWsWidth;
-
- cr.arc(leftX, height / 2, workspaceRadius, 0, Math.PI * 2); // Should be 0.5 * Math.PI, 1.5 * Math.PI in theory but it leaves a weird 1px gap
- cr.fill();
- cr.rectangle(leftX, height / 2 - workspaceRadius, activeWsWidth, workspaceDiameter);
- cr.fill();
- cr.arc(leftX + activeWsWidth, height / 2, workspaceRadius, 0, Math.PI * 2);
- cr.fill();
- }
- else { // To left
- const immediateActiveWs = floor(activeWs);
- widthPercentage = 1 - (activeWs - immediateActiveWs);
- leftX = -workspaceRadius + (workspaceDiameter * WS_TAKEN_WIDTH_MULTIPLIER * immediateActiveWs);
- activeWsWidth = (activeWorkspaceWidth - (workspaceDiameter * 1.5)) * widthPercentage
-
- cr.arc(leftX, height / 2, workspaceRadius, 0, Math.PI * 2); // Should be 0.5 * Math.PI, 1.5 * Math.PI in theory but it leaves a weird 1px gap
- cr.fill();
- cr.rectangle(leftX, height / 2 - workspaceRadius, activeWsWidth, workspaceDiameter);
- cr.fill();
- cr.arc(leftX + activeWsWidth, height / 2, workspaceRadius, 0, Math.PI * 2);
- cr.fill();
- }
- }))
- ,
- })
-}
-
-export default () => EventBox({
- onScrollUp: () => Hyprland.messageAsync(`dispatch workspace r-1`).catch(print),
- onScrollDown: () => Hyprland.messageAsync(`dispatch workspace r+1`).catch(print),
- onMiddleClick: () => toggleWindowOnAllMonitors('osk'),
- onSecondaryClick: () => App.toggleWindow('overview'),
- attribute: {
- clicked: false,
- ws_group: 0,
- },
- child: Box({
- homogeneous: true,
- // className: 'bar-group-margin',
- children: [Box({
- // className: `bar-group${userOptions.appearance.borderless ? '-borderless' : ''} bar-group-standalone bar-group-pad`,
- css: 'min-width: 2px;',
- children: [WorkspaceContents(userOptions.workspaces.shown)],
- })]
- }),
- setup: (self) => {
- self.add_events(Gdk.EventMask.POINTER_MOTION_MASK);
- self.on('motion-notify-event', (self, event) => {
- if (!self.attribute.clicked) return;
- const [_, cursorX, cursorY] = event.get_coords();
- const widgetWidth = self.get_allocation().width;
- const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth);
- Utils.execAsync([`${App.configDir}/scripts/hyprland/workspace_action.sh`, 'workspace', `${wsId}`])
- .catch(print);
- })
- self.on('button-press-event', (self, event) => {
- if (!(event.get_button()[1] === 1)) return; // We're only interested in left-click here
- self.attribute.clicked = true;
- const [_, cursorX, cursorY] = event.get_coords();
- const widgetWidth = self.get_allocation().width;
- // const wsId = Math.ceil(cursorX * NUM_OF_WORKSPACES_PER_GROUP / widgetWidth) + self.attribute.ws_group * NUM_OF_WORKSPACES_PER_GROUP;
- // Hyprland.messageAsync(`dispatch workspace ${wsId}`).catch(print);
- const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth);
- Utils.execAsync([`${App.configDir}/scripts/hyprland/workspace_action.sh`, 'workspace', `${wsId}`])
- .catch(print);
- })
- self.on('button-release-event', (self) => self.attribute.clicked = false);
- }
-})
diff --git a/.config/ags/modules/bar/focus/workspaces_sway.js b/.config/ags/modules/bar/focus/workspaces_sway.js
deleted file mode 100644
index e883ece55..000000000
--- a/.config/ags/modules/bar/focus/workspaces_sway.js
+++ /dev/null
@@ -1,183 +0,0 @@
-const { GLib, Gdk, Gtk } = imports.gi;
-const Lang = imports.lang;
-const Cairo = imports.cairo;
-const Pango = imports.gi.Pango;
-const PangoCairo = imports.gi.PangoCairo;
-import Widget from "resource:///com/github/Aylur/ags/widget.js";
-import Sway from "../../../services/sway.js";
-import * as Utils from "resource:///com/github/Aylur/ags/utils.js";
-const { execAsync, exec } = Utils;
-const { Box, DrawingArea, EventBox } = Widget;
-
-const dummyWs = Box({ className: 'bar-ws' }); // Not shown. Only for getting size props
-const dummyActiveWs = Box({ className: 'bar-ws bar-ws-active' }); // Not shown. Only for getting size props
-const dummyOccupiedWs = Box({ className: 'bar-ws bar-ws-occupied' }); // Not shown. Only for getting size props
-
-const switchToWorkspace = (arg) => Utils.execAsync(`swaymsg workspace ${arg}`).catch(print);
-const switchToRelativeWorkspace = (self, num) =>
- execAsync([`${App.configDir}/scripts/sway/swayToRelativeWs.sh`, `${num}`]).catch(print);
-
-const WorkspaceContents = (count = 10) => {
- return DrawingArea({
- css: `transition: 90ms cubic-bezier(0.1, 1, 0, 1);`,
- attribute: {
- initialized: false,
- workspaceMask: 0,
- updateMask: (self) => {
- if (self.attribute.initialized) return; // We only need this to run once
- const workspaces = Sway.workspaces;
- let workspaceMask = 0;
- // console.log('----------------')
- for (let i = 0; i < workspaces.length; i++) {
- const ws = workspaces[i];
- // console.log(ws.name, ',', ws.num);
- if (!Number(ws.name)) return;
- const id = Number(ws.name);
- if (id <= 0) continue; // Ignore scratchpads
- if (id > count) return; // Not rendered
- if (workspaces[i].windows > 0) {
- workspaceMask |= (1 << id);
- }
- }
- self.attribute.workspaceMask = workspaceMask;
- self.attribute.initialized = true;
- },
- toggleMask: (self, occupied, name) => {
- if (occupied) self.attribute.workspaceMask |= (1 << parseInt(name));
- else self.attribute.workspaceMask &= ~(1 << parseInt(name));
- },
- },
- setup: (area) => area
- .hook(Sway.active.workspace, (area) => {
- area.setCss(`font-size: ${Sway.active.workspace.name}px;`)
- })
- .hook(Sway, (self) => self.attribute.updateMask(self), 'notify::workspaces')
- // .hook(Hyprland, (self, name) => self.attribute.toggleMask(self, true, name), 'workspace-added')
- // .hook(Hyprland, (self, name) => self.attribute.toggleMask(self, false, name), 'workspace-removed')
- .on('draw', Lang.bind(area, (area, cr) => {
- const allocation = area.get_allocation();
- const { width, height } = allocation;
-
- const workspaceStyleContext = dummyWs.get_style_context();
- const workspaceDiameter = workspaceStyleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
- const workspaceRadius = workspaceDiameter / 2;
- const workspaceFontSize = workspaceStyleContext.get_property('font-size', Gtk.StateFlags.NORMAL) / 4 * 3;
- const workspaceFontFamily = workspaceStyleContext.get_property('font-family', Gtk.StateFlags.NORMAL);
- const wsbg = workspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
- const wsfg = workspaceStyleContext.get_property('color', Gtk.StateFlags.NORMAL);
-
- const occupiedWorkspaceStyleContext = dummyOccupiedWs.get_style_context();
- const occupiedbg = occupiedWorkspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
- const occupiedfg = occupiedWorkspaceStyleContext.get_property('color', Gtk.StateFlags.NORMAL);
-
- const activeWorkspaceStyleContext = dummyActiveWs.get_style_context();
- const activebg = activeWorkspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
- const activefg = activeWorkspaceStyleContext.get_property('color', Gtk.StateFlags.NORMAL);
- area.set_size_request(workspaceDiameter * count, -1);
- const widgetStyleContext = area.get_style_context();
- const activeWs = widgetStyleContext.get_property('font-size', Gtk.StateFlags.NORMAL);
-
- const activeWsCenterX = -(workspaceDiameter / 2) + (workspaceDiameter * activeWs);
- const activeWsCenterY = height / 2;
-
- // Font
- const layout = PangoCairo.create_layout(cr);
- const fontDesc = Pango.font_description_from_string(`${workspaceFontFamily[0]} ${workspaceFontSize}`);
- layout.set_font_description(fontDesc);
- cr.setAntialias(Cairo.Antialias.BEST);
- // Get kinda min radius for number indicators
- layout.set_text("0".repeat(count.toString().length), -1);
- const [layoutWidth, layoutHeight] = layout.get_pixel_size();
- const indicatorRadius = Math.max(layoutWidth, layoutHeight) / 2 * 1.2; // a bit smaller than sqrt(2)*radius
- const indicatorGap = workspaceRadius - indicatorRadius;
-
- // Draw workspace numbers
- for (let i = 1; i <= count; i++) {
- if (area.attribute.workspaceMask & (1 << i)) {
- // Draw bg highlight
- cr.setSourceRGBA(occupiedbg.red, occupiedbg.green, occupiedbg.blue, occupiedbg.alpha);
- const wsCenterX = -(workspaceRadius) + (workspaceDiameter * i);
- const wsCenterY = height / 2;
- if (!(area.attribute.workspaceMask & (1 << (i - 1)))) { // Left
- cr.arc(wsCenterX, wsCenterY, workspaceRadius, 0.5 * Math.PI, 1.5 * Math.PI);
- cr.fill();
- }
- else {
- cr.rectangle(wsCenterX - workspaceRadius, wsCenterY - workspaceRadius, workspaceRadius, workspaceRadius * 2)
- cr.fill();
- }
- if (!(area.attribute.workspaceMask & (1 << (i + 1)))) { // Right
- cr.arc(wsCenterX, wsCenterY, workspaceRadius, -0.5 * Math.PI, 0.5 * Math.PI);
- cr.fill();
- }
- else {
- cr.rectangle(wsCenterX, wsCenterY - workspaceRadius, workspaceRadius, workspaceRadius * 2)
- cr.fill();
- }
-
- // Set color for text
- cr.setSourceRGBA(occupiedfg.red, occupiedfg.green, occupiedfg.blue, occupiedfg.alpha);
- }
- else
- cr.setSourceRGBA(wsfg.red, wsfg.green, wsfg.blue, wsfg.alpha);
- layout.set_text(`${i}`, -1);
- const [layoutWidth, layoutHeight] = layout.get_pixel_size();
- const x = -workspaceRadius + (workspaceDiameter * i) - (layoutWidth / 2);
- const y = (height - layoutHeight) / 2;
- cr.moveTo(x, y);
- // cr.showText(text);
- PangoCairo.show_layout(cr, layout);
- cr.stroke();
- }
-
- // Draw active ws
- // base
- cr.setSourceRGBA(activebg.red, activebg.green, activebg.blue, activebg.alpha);
- cr.arc(activeWsCenterX, activeWsCenterY, indicatorRadius, 0, 2 * Math.PI);
- cr.fill();
- // inner decor
- cr.setSourceRGBA(activefg.red, activefg.green, activefg.blue, activefg.alpha);
- cr.arc(activeWsCenterX, activeWsCenterY, indicatorRadius * 0.2, 0, 2 * Math.PI);
- cr.fill();
- }))
- ,
- })
-}
-
-export default () => EventBox({
- onScrollUp: (self) => switchToRelativeWorkspace(self, -1),
- onScrollDown: (self) => switchToRelativeWorkspace(self, +1),
- onMiddleClick: () => toggleWindowOnAllMonitors('osk'),
- onSecondaryClick: () => App.toggleWindow('overview'),
- attribute: { clicked: false },
- child: Box({
- homogeneous: true,
- className: 'bar-group-margin',
- children: [Box({
- className: `bar-group${userOptions.appearance.borderless ? '-borderless' : ''} bar-group-standalone bar-group-pad`,
- css: 'min-width: 2px;',
- children: [
- WorkspaceContents(10),
- ]
- })]
- }),
- setup: (self) => {
- self.add_events(Gdk.EventMask.POINTER_MOTION_MASK);
- self.on('motion-notify-event', (self, event) => {
- if (!self.attribute.clicked) return;
- const [_, cursorX, cursorY] = event.get_coords();
- const widgetWidth = self.get_allocation().width;
- const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth);
- switchToWorkspace(wsId);
- })
- self.on('button-press-event', (self, event) => {
- if (!(event.get_button()[1] === 1)) return; // We're only interested in left-click here
- self.attribute.clicked = true;
- const [_, cursorX, cursorY] = event.get_coords();
- const widgetWidth = self.get_allocation().width;
- const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth);
- switchToWorkspace(wsId);
- })
- self.on('button-release-event', (self) => self.attribute.clicked = false);
- }
-});
diff --git a/.config/ags/modules/bar/main.js b/.config/ags/modules/bar/main.js
deleted file mode 100644
index 771306e86..000000000
--- a/.config/ags/modules/bar/main.js
+++ /dev/null
@@ -1,129 +0,0 @@
-const { Gtk } = imports.gi;
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import Battery from 'resource:///com/github/Aylur/ags/service/battery.js';
-
-import WindowTitle from "./normal/spaceleft.js";
-import Indicators from "./normal/spaceright.js";
-import Music from "./normal/music.js";
-import System from "./normal/system.js";
-import { enableClickthrough } from "../.widgetutils/clickthrough.js";
-import { RoundedCorner } from "../.commonwidgets/cairo_roundedcorner.js";
-import { currentShellMode } from '../../variables.js';
-
-const NormalOptionalWorkspaces = async () => {
- try {
- return (await import('./normal/workspaces_hyprland.js')).default();
- } catch {
- try {
- return (await import('./normal/workspaces_sway.js')).default();
- } catch {
- return null;
- }
- }
-};
-
-const FocusOptionalWorkspaces = async () => {
- try {
- return (await import('./focus/workspaces_hyprland.js')).default();
- } catch {
- try {
- return (await import('./focus/workspaces_sway.js')).default();
- } catch {
- return null;
- }
- }
-};
-
-export const Bar = async (monitor = 0) => {
- const SideModule = (children) => Widget.Box({
- className: 'bar-sidemodule',
- children: children,
- });
- const normalBarContent = Widget.CenterBox({
- className: 'bar-bg',
- setup: (self) => {
- const styleContext = self.get_style_context();
- const minHeight = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
- // execAsync(['bash', '-c', `hyprctl keyword monitor ,addreserved,${minHeight},0,0,0`]).catch(print);
- },
- startWidget: (await WindowTitle(monitor)),
- centerWidget: Widget.Box({
- className: 'spacing-h-4',
- children: [
- SideModule([Music()]),
- Widget.Box({
- homogeneous: true,
- children: [await NormalOptionalWorkspaces()],
- }),
- SideModule([System()]),
- ]
- }),
- endWidget: Indicators(monitor),
- });
- const focusedBarContent = Widget.CenterBox({
- className: 'bar-bg-focus',
- startWidget: Widget.Box({}),
- centerWidget: Widget.Box({
- className: 'spacing-h-4',
- children: [
- SideModule([]),
- Widget.Box({
- homogeneous: true,
- children: [await FocusOptionalWorkspaces()],
- }),
- SideModule([]),
- ]
- }),
- endWidget: Widget.Box({}),
- setup: (self) => {
- self.hook(Battery, (self) => {
- if (!Battery.available) return;
- self.toggleClassName('bar-bg-focus-batterylow', Battery.percent <= userOptions.battery.low);
- })
- }
- });
- const nothingContent = Widget.Box({
- className: 'bar-bg-nothing',
- })
- return Widget.Window({
- monitor,
- name: `bar${monitor}`,
- anchor: ['top', 'left', 'right'],
- exclusivity: 'exclusive',
- visible: true,
- child: Widget.Stack({
- homogeneous: false,
- transition: 'slide_up_down',
- transitionDuration: userOptions.animations.durationLarge,
- children: {
- 'normal': normalBarContent,
- 'focus': focusedBarContent,
- 'nothing': nothingContent,
- },
- setup: (self) => self.hook(currentShellMode, (self) => {
- self.shown = currentShellMode.value[monitor];
- })
- }),
- });
-}
-
-export const BarCornerTopleft = (monitor = 0) => Widget.Window({
- monitor,
- name: `barcornertl${monitor}`,
- layer: 'top',
- anchor: ['top', 'left'],
- exclusivity: 'normal',
- visible: true,
- child: RoundedCorner('topleft', { className: 'corner', }),
- setup: enableClickthrough,
-});
-export const BarCornerTopright = (monitor = 0) => Widget.Window({
- monitor,
- name: `barcornertr${monitor}`,
- layer: 'top',
- anchor: ['top', 'right'],
- exclusivity: 'normal',
- visible: true,
- child: RoundedCorner('topright', { className: 'corner', }),
- setup: enableClickthrough,
-});
diff --git a/.config/ags/modules/bar/normal/music.js b/.config/ags/modules/bar/normal/music.js
deleted file mode 100644
index 88c9bf816..000000000
--- a/.config/ags/modules/bar/normal/music.js
+++ /dev/null
@@ -1,241 +0,0 @@
-const { GLib } = imports.gi;
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js';
-const { Box, Button, EventBox, Label, Overlay, Revealer } = Widget;
-const { execAsync, exec } = Utils;
-import { AnimatedCircProg } from "../../.commonwidgets/cairo_circularprogress.js";
-import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
-import { showMusicControls } from '../../../variables.js';
-
-const CUSTOM_MODULE_CONTENT_INTERVAL_FILE = `${GLib.get_user_cache_dir()}/ags/user/scripts/custom-module-interval.txt`;
-const CUSTOM_MODULE_CONTENT_SCRIPT = `${GLib.get_user_cache_dir()}/ags/user/scripts/custom-module-poll.sh`;
-const CUSTOM_MODULE_LEFTCLICK_SCRIPT = `${GLib.get_user_cache_dir()}/ags/user/scripts/custom-module-leftclick.sh`;
-const CUSTOM_MODULE_RIGHTCLICK_SCRIPT = `${GLib.get_user_cache_dir()}/ags/user/scripts/custom-module-rightclick.sh`;
-const CUSTOM_MODULE_MIDDLECLICK_SCRIPT = `${GLib.get_user_cache_dir()}/ags/user/scripts/custom-module-middleclick.sh`;
-const CUSTOM_MODULE_SCROLLUP_SCRIPT = `${GLib.get_user_cache_dir()}/ags/user/scripts/custom-module-scrollup.sh`;
-const CUSTOM_MODULE_SCROLLDOWN_SCRIPT = `${GLib.get_user_cache_dir()}/ags/user/scripts/custom-module-scrolldown.sh`;
-
-function trimTrackTitle(title) {
- if (!title) return '';
- const cleanPatterns = [
- /【[^】]*】/, // Touhou n weeb stuff
- " [FREE DOWNLOAD]", // F-777
- ];
- cleanPatterns.forEach((expr) => title = title.replace(expr, ''));
- return title;
-}
-
-function adjustVolume(direction) {
- const step = 0.1; // We use a larger step because this is player instance volume, not global
- const mpris = Mpris.getPlayer('');
- mpris.volume += (direction === 'up') ? step : -step
-}
-
-
-const BarGroup = ({ child }) => Box({
- className: 'bar-group-margin bar-sides',
- children: [
- Box({
- className: `bar-group${userOptions.appearance.borderless ? '-borderless' : ''} bar-group-standalone bar-group-pad-system`,
- children: [child],
- }),
- ]
-});
-
-const BarResource = (name, icon, command, circprogClassName = `bar-batt-circprog ${userOptions.appearance.borderless ? 'bar-batt-circprog-borderless' : ''}`, textClassName = 'txt-onSurfaceVariant', iconClassName = 'bar-batt') => {
- const resourceCircProg = AnimatedCircProg({
- className: `${circprogClassName}`,
- vpack: 'center',
- hpack: 'center',
- });
- const resourceProgress = Box({
- homogeneous: true,
- children: [Overlay({
- child: Box({
- vpack: 'center',
- className: `${iconClassName}`,
- homogeneous: true,
- children: [
- MaterialIcon(icon, 'small'),
- ],
- }),
- overlays: [resourceCircProg]
- })]
- });
- const resourceLabel = Label({
- className: `txt-smallie ${textClassName}`,
- });
- const widget = Button({
- onClicked: () => Utils.execAsync(['bash', '-c', `${userOptions.apps.taskManager}`]).catch(print),
- child: Box({
- className: `spacing-h-4 ${textClassName}`,
- children: [
- resourceProgress,
- resourceLabel,
- ],
- setup: (self) => self.poll(5000, () => execAsync(['bash', '-c', command])
- .then((output) => {
- resourceCircProg.css = `font-size: ${Number(output)}px;`;
- resourceLabel.label = `${Math.round(Number(output))}%`;
- widget.tooltipText = `${name}: ${Math.round(Number(output))}%`;
- }).catch(print))
- ,
- })
- });
- return widget;
-}
-
-const TrackProgress = () => {
- const _updateProgress = (circprog) => {
- const mpris = Mpris.getPlayer('');
- if (!mpris)
- circprog.css = `font-size: ${userOptions.appearance.borderless ? 100 : 0}px;`
- else // Set circular progress value
- circprog.css = `font-size: ${Math.max(mpris.position / mpris.length * 100, 0)}px;`
- }
- return AnimatedCircProg({
- className: `bar-music-circprog ${userOptions.appearance.borderless ? 'bar-music-circprog-borderless' : ''}`,
- vpack: 'center', hpack: 'center',
- extraSetup: (self) => self
- .hook(Mpris, _updateProgress)
- .poll(3000, _updateProgress)
- ,
- })
-}
-
-const switchToRelativeWorkspace = async (self, num) => {
- try {
- const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
- Hyprland.messageAsync(`dispatch workspace ${num > 0 ? '+' : ''}${num}`).catch(print);
- } catch {
- execAsync([`${App.configDir}/scripts/sway/swayToRelativeWs.sh`, `${num}`]).catch(print);
- }
-}
-
-
-
-export default () => {
- // TODO: use cairo to make button bounce smaller on click, if that's possible
- const playingState = Box({ // Wrap a box cuz overlay can't have margins itself
- homogeneous: true,
- children: [Overlay({
- child: Box({
- vpack: 'center',
- className: 'bar-music-playstate',
- homogeneous: true,
- children: [Label({
- vpack: 'center',
- className: 'bar-music-playstate-txt',
- justification: 'center',
- setup: (self) => self.hook(Mpris, label => {
- const mpris = Mpris.getPlayer('');
- label.label = `${mpris !== null && mpris.playBackStatus == 'Playing' ? 'pause' : 'play_arrow'}`;
- }),
- })],
- setup: (self) => self.hook(Mpris, label => {
- const mpris = Mpris.getPlayer('');
- if (!mpris) return;
- label.toggleClassName('bar-music-playstate-playing', mpris.playBackStatus == 'Playing');
- label.toggleClassName('bar-music-playstate', mpris.playBackStatus == 'Paused');
- }),
- }),
- overlays: [
- TrackProgress(),
- ]
- })]
- });
- const trackTitle = Label({
- hexpand: true,
- className: 'txt-smallie bar-music-txt',
- truncate: 'end',
- maxWidthChars: 1, // Doesn't matter, just needs to be non negative
- setup: (self) => self.hook(Mpris, label => {
- const mpris = Mpris.getPlayer('');
- if (mpris)
- label.label = `${trimTrackTitle(mpris.trackTitle)} • ${mpris.trackArtists.join(', ')}`;
- else
- label.label = getString('No media');
- }),
- })
- const musicStuff = Box({
- className: 'spacing-h-10',
- hexpand: true,
- children: [
- playingState,
- trackTitle,
- ]
- })
- const SystemResourcesOrCustomModule = () => {
- // Check if $XDG_CACHE_HOME/ags/user/scripts/custom-module-poll.sh exists
- if (GLib.file_test(CUSTOM_MODULE_CONTENT_SCRIPT, GLib.FileTest.EXISTS)) {
- const interval = Number(Utils.readFile(CUSTOM_MODULE_CONTENT_INTERVAL_FILE)) || 5000;
- return BarGroup({
- child: Button({
- child: Label({
- className: 'txt-smallie txt-onSurfaceVariant',
- useMarkup: true,
- setup: (self) => Utils.timeout(1, () => {
- self.label = exec(CUSTOM_MODULE_CONTENT_SCRIPT);
- self.poll(interval, (self) => {
- const content = exec(CUSTOM_MODULE_CONTENT_SCRIPT);
- self.label = content;
- })
- })
- }),
- onPrimaryClickRelease: () => execAsync(CUSTOM_MODULE_LEFTCLICK_SCRIPT).catch(print),
- onSecondaryClickRelease: () => execAsync(CUSTOM_MODULE_RIGHTCLICK_SCRIPT).catch(print),
- onMiddleClickRelease: () => execAsync(CUSTOM_MODULE_MIDDLECLICK_SCRIPT).catch(print),
- onScrollUp: () => execAsync(CUSTOM_MODULE_SCROLLUP_SCRIPT).catch(print),
- onScrollDown: () => execAsync(CUSTOM_MODULE_SCROLLDOWN_SCRIPT).catch(print),
- })
- });
- } else return BarGroup({
- child: Box({
- children: [
- BarResource(getString('RAM Usage'), 'memory', `LANG=C free | awk '/^Mem/ {printf("%.2f\\n", ($3/$2) * 100)}'`,
- `bar-ram-circprog ${userOptions.appearance.borderless ? 'bar-ram-circprog-borderless' : ''}`, 'bar-ram-txt', 'bar-ram-icon'),
- Revealer({
- revealChild: true,
- transition: 'slide_left',
- transitionDuration: userOptions.animations.durationLarge,
- child: Box({
- className: 'spacing-h-10 margin-left-10',
- children: [
- BarResource(getString('Swap Usage'), 'swap_horiz', `LANG=C free | awk '/^Swap/ {if ($2 > 0) printf("%.2f\\n", ($3/$2) * 100); else print "0";}'`,
- `bar-swap-circprog ${userOptions.appearance.borderless ? 'bar-swap-circprog-borderless' : ''}`, 'bar-swap-txt', 'bar-swap-icon'),
- BarResource(getString('CPU Usage'), 'settings_motion_mode', `LANG=C top -bn1 | grep Cpu | sed 's/\\,/\\./g' | awk '{print $2}'`,
- `bar-cpu-circprog ${userOptions.appearance.borderless ? 'bar-cpu-circprog-borderless' : ''}`, 'bar-cpu-txt', 'bar-cpu-icon'),
- ]
- }),
- setup: (self) => self.hook(Mpris, label => {
- const mpris = Mpris.getPlayer('');
- self.revealChild = (!mpris || mpris.playBackStatus !== 'Playing' || userOptions.bar.alwaysShowFullResources);
- }),
- })
- ],
- })
- });
- }
- return EventBox({
- onScrollUp: () => adjustVolume('up'),
- onScrollDown: () => adjustVolume('down'),
- child: Box({
- className: 'spacing-h-4',
- children: [
- SystemResourcesOrCustomModule(),
- EventBox({
- child: BarGroup({ child: musicStuff }),
- onPrimaryClick: () => showMusicControls.setValue(!showMusicControls.value),
- onSecondaryClick: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']).catch(print),
- onMiddleClick: () => execAsync('playerctl play-pause').catch(print),
- setup: (self) => self.on('button-press-event', (self, event) => {
- if (event.get_button()[1] === 8) // Side button
- execAsync('playerctl previous').catch(print)
- }),
- })
- ]
- })
- });
-}
-
diff --git a/.config/ags/modules/bar/normal/spaceleft.js b/.config/ags/modules/bar/normal/spaceleft.js
deleted file mode 100644
index d7f861271..000000000
--- a/.config/ags/modules/bar/normal/spaceleft.js
+++ /dev/null
@@ -1,96 +0,0 @@
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import Brightness from '../../../services/brightness.js';
-import Indicator from '../../../services/indicator.js';
-import { distance } from '../../.miscutils/mathfuncs.js';
-
-const OSD_DISMISS_DISTANCE = 10;
-
-const WindowTitle = async () => {
- try {
- const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
- return Widget.Scrollable({
- hexpand: true, vexpand: true,
- hscroll: 'automatic', vscroll: 'never',
- child: Widget.Box({
- vertical: true,
- children: [
- Widget.Label({
- xalign: 0,
- truncate: 'end',
- maxWidthChars: 1, // Doesn't matter, just needs to be non negative
- className: 'txt-smaller bar-wintitle-topdesc txt',
- setup: (self) => self.hook(Hyprland.active.client, label => { // Hyprland.active.client
- label.label = Hyprland.active.client.class.length === 0 ? 'Desktop' : Hyprland.active.client.class;
- }),
- }),
- Widget.Label({
- xalign: 0,
- truncate: 'end',
- maxWidthChars: 1, // Doesn't matter, just needs to be non negative
- className: 'txt-smallie bar-wintitle-txt',
- setup: (self) => {
- self.hook(Hyprland.active.client, label => { // Hyprland.active.client
- label.label = Hyprland.active.client.title.length === 0 ? `Workspace ${Hyprland.active.workspace.id}` : Hyprland.active.client.title;
- });
- self.hook(Hyprland.active.workspace, label => { // Hyprland.active.client
- label.label = Hyprland.active.client.title.length === 0 ? `Workspace ${Hyprland.active.workspace.id}` : Hyprland.active.client.title;
- });
- }
- })
- ]
- })
- });
- } catch {
- return null;
- }
-}
-
-
-export default async (monitor = 0) => {
- const optionalWindowTitleInstance = await WindowTitle();
- let scrollCursorX, scrollCursorY;
- return Widget.EventBox({
- onScrollUp: (self, event) => {
- let _;
- [_, scrollCursorX, scrollCursorY] = event.get_coords();
- Indicator.popup(1); // Since the brightness and speaker are both on the same window
- Brightness[monitor].screen_value += 0.05;
- },
- onScrollDown: (self, event) => {
- let _;
- [_, scrollCursorX, scrollCursorY] = event.get_coords();
- Indicator.popup(1); // Since the brightness and speaker are both on the same window
- Brightness[monitor].screen_value -= 0.05;
- },
- onPrimaryClick: () => {
- App.toggleWindow('sideleft');
- },
- setup: (self) => self.on('motion-notify-event', (self, event) => {
- const [_, cursorX, cursorY] = event.get_coords();
- if (distance(cursorX, cursorY, scrollCursorX, scrollCursorY) >= OSD_DISMISS_DISTANCE)
- Indicator.popup(-1);
- }),
- child: Widget.Box({
- homogeneous: false,
- children: [
- Widget.Box({ className: 'bar-corner-spacing' }),
- Widget.Overlay({
- overlays: [
- Widget.Box({ hexpand: true }),
- Widget.Box({
- className: 'bar-sidemodule', hexpand: true,
- children: [Widget.Box({
- vertical: true,
- className: 'bar-space-button',
- children: [
- optionalWindowTitleInstance,
- ]
- })]
- }),
- ]
- })
- ]
- })
- });
-}
diff --git a/.config/ags/modules/bar/normal/spaceright.js b/.config/ags/modules/bar/normal/spaceright.js
deleted file mode 100644
index dd23de33c..000000000
--- a/.config/ags/modules/bar/normal/spaceright.js
+++ /dev/null
@@ -1,106 +0,0 @@
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-
-import Audio from 'resource:///com/github/Aylur/ags/service/audio.js';
-import SystemTray from 'resource:///com/github/Aylur/ags/service/systemtray.js';
-const { execAsync } = Utils;
-import Indicator from '../../../services/indicator.js';
-import { StatusIcons } from '../../.commonwidgets/statusicons.js';
-import { Tray } from "./tray.js";
-import { distance } from '../../.miscutils/mathfuncs.js';
-
-const OSD_DISMISS_DISTANCE = 10;
-
-const SeparatorDot = () => Widget.Revealer({
- transition: 'slide_left',
- revealChild: false,
- attribute: {
- 'count': SystemTray.items.length,
- 'update': (self, diff) => {
- self.attribute.count += diff;
- self.revealChild = (self.attribute.count > 0);
- }
- },
- child: Widget.Box({
- vpack: 'center',
- className: 'separator-circle',
- }),
- setup: (self) => self
- .hook(SystemTray, (self) => self.attribute.update(self, 1), 'added')
- .hook(SystemTray, (self) => self.attribute.update(self, -1), 'removed')
- ,
-});
-
-export default (monitor = 0) => {
- const barTray = Tray();
- const barStatusIcons = StatusIcons({
- className: 'bar-statusicons',
- setup: (self) => self.hook(App, (self, currentName, visible) => {
- if (currentName === 'sideright') {
- self.toggleClassName('bar-statusicons-active', visible);
- }
- }),
- }, monitor);
- const SpaceRightInteractions = (child) => Widget.EventBox({
- onHover: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', true) },
- onHoverLost: () => { barStatusIcons.toggleClassName('bar-statusicons-hover', false) },
- onPrimaryClick: () => App.toggleWindow('sideright'),
- onSecondaryClick: () => execAsync(['bash', '-c', 'playerctl next || playerctl position `bc <<< "100 * $(playerctl metadata mpris:length) / 1000000 / 100"` &']).catch(print),
- onMiddleClick: () => execAsync('playerctl play-pause').catch(print),
- setup: (self) => self.on('button-press-event', (self, event) => {
- if (event.get_button()[1] === 8)
- execAsync('playerctl previous').catch(print)
- }).on('motion-notify-event', (self, event) => {
- Indicator.popup(-1);
- }),
- child: child,
- });
- const emptyArea = SpaceRightInteractions(Widget.Box({ hexpand: true, }));
- const indicatorArea = SpaceRightInteractions(Widget.Box({
- children: [
- SeparatorDot(),
- barStatusIcons
- ],
- }));
- const actualContent = Widget.Box({
- hexpand: true,
- className: 'spacing-h-5 bar-spaceright',
- children: [
- emptyArea,
- barTray,
- indicatorArea
- ],
- });
-
- let scrollCursorX, scrollCursorY;
- return Widget.EventBox({
- onScrollUp: (self, event) => {
- if (!Audio.speaker) return;
- let _;
- [_, scrollCursorX, scrollCursorY] = event.get_coords();
- if (Audio.speaker.volume <= 0.09) Audio.speaker.volume += 0.01;
- else Audio.speaker.volume += 0.03;
- Indicator.popup(1);
- },
- onScrollDown: (self, event) => {
- if (!Audio.speaker) return;
- let _;
- [_, scrollCursorX, scrollCursorY] = event.get_coords();
- if (Audio.speaker.volume <= 0.09) Audio.speaker.volume -= 0.01;
- else Audio.speaker.volume -= 0.03;
- Indicator.popup(1);
- },
- setup: (self) => self.on('motion-notify-event', (self, event) => {
- const [_, cursorX, cursorY] = event.get_coords();
- if (distance(cursorX, cursorY, scrollCursorX, scrollCursorY) >= OSD_DISMISS_DISTANCE)
- Indicator.popup(-1);
- }),
- child: Widget.Box({
- children: [
- actualContent,
- SpaceRightInteractions(Widget.Box({ className: 'bar-corner-spacing' })),
- ]
- })
- });
-}
\ No newline at end of file
diff --git a/.config/ags/modules/bar/normal/system.js b/.config/ags/modules/bar/normal/system.js
deleted file mode 100644
index c69abe685..000000000
--- a/.config/ags/modules/bar/normal/system.js
+++ /dev/null
@@ -1,238 +0,0 @@
-// This is for the right pills of the bar.
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { Box, Label, Button, Overlay, Revealer, Scrollable, Stack, EventBox } = Widget;
-const { exec, execAsync } = Utils;
-const { GLib } = imports.gi;
-import Battery from 'resource:///com/github/Aylur/ags/service/battery.js';
-import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
-import { AnimatedCircProg } from "../../.commonwidgets/cairo_circularprogress.js";
-import { WWO_CODE, WEATHER_SYMBOL, NIGHT_WEATHER_SYMBOL } from '../../.commondata/weather.js';
-import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
-
-const WEATHER_CACHE_FOLDER = `${GLib.get_user_cache_dir()}/ags/weather`;
-Utils.exec(`mkdir -p ${WEATHER_CACHE_FOLDER}`);
-
-const BarBatteryProgress = () => {
- const _updateProgress = (circprog) => { // Set circular progress value
- circprog.css = `font-size: ${Math.abs(Battery.percent)}px;`
-
- circprog.toggleClassName('bar-batt-circprog-low', Battery.percent <= userOptions.battery.low);
- circprog.toggleClassName('bar-batt-circprog-full', Battery.charged);
- }
- return AnimatedCircProg({
- className: `bar-batt-circprog ${userOptions.appearance.borderless ? 'bar-batt-circprog-borderless' : ''}`,
- vpack: 'center', hpack: 'center',
- extraSetup: (self) => self
- .hook(Battery, _updateProgress)
- ,
- })
-}
-
-const time = Variable('', {
- poll: [
- userOptions.time.interval,
- () => GLib.DateTime.new_now_local().format(userOptions.time.format),
- ],
-})
-
-const date = Variable('', {
- poll: [
- userOptions.time.dateInterval,
- () => GLib.DateTime.new_now_local().format(userOptions.time.dateFormatLong),
- ],
-})
-
-const BarClock = () => Widget.Box({
- vpack: 'center',
- className: 'spacing-h-4 bar-clock-box',
- children: [
- Widget.Label({
- className: 'bar-time',
- label: time.bind(),
- }),
- Widget.Label({
- className: 'txt-norm txt-onLayer1',
- label: '•',
- }),
- Widget.Label({
- className: 'txt-smallie bar-date',
- label: date.bind(),
- }),
- ],
-});
-
-const UtilButton = ({ name, icon, onClicked }) => Button({
- vpack: 'center',
- tooltipText: name,
- onClicked: onClicked,
- className: `bar-util-btn ${userOptions.appearance.borderless ? 'bar-util-btn-borderless' : ''} icon-material txt-norm`,
- label: `${icon}`,
- setup: setupCursorHover
-})
-
-const Utilities = () => Box({
- hpack: 'center',
- className: 'spacing-h-4',
- children: [
- UtilButton({
- name: getString('Screen snip'), icon: 'screenshot_region', onClicked: () => {
- Utils.execAsync(`${App.configDir}/scripts/grimblast.sh copy area`)
- .catch(print)
- }
- }),
- UtilButton({
- name: getString('Color picker'), icon: 'colorize', onClicked: () => {
- Utils.execAsync(['hyprpicker', '-a']).catch(print)
- }
- }),
- UtilButton({
- name: getString('Toggle on-screen keyboard'), icon: 'keyboard', onClicked: () => {
- toggleWindowOnAllMonitors('osk');
- }
- }),
- ]
-})
-
-const BarBattery = () => Box({
- className: 'spacing-h-4 bar-batt-txt',
- children: [
- Revealer({
- transitionDuration: userOptions.animations.durationSmall,
- revealChild: false,
- transition: 'slide_right',
- child: MaterialIcon('bolt', 'norm', { tooltipText: "Charging" }),
- setup: (self) => self.hook(Battery, revealer => {
- self.revealChild = Battery.charging;
- }),
- }),
- Label({
- className: 'txt-smallie',
- setup: (self) => self.hook(Battery, label => {
- label.label = `${Number.parseFloat(Battery.percent.toFixed(1))}%`;
- }),
- }),
- Overlay({
- child: Widget.Box({
- vpack: 'center',
- className: 'bar-batt',
- homogeneous: true,
- children: [
- MaterialIcon('battery_full', 'small'),
- ],
- setup: (self) => self.hook(Battery, box => {
- box.toggleClassName('bar-batt-low', Battery.percent <= userOptions.battery.low);
- box.toggleClassName('bar-batt-full', Battery.charged);
- }),
- }),
- overlays: [
- BarBatteryProgress(),
- ]
- }),
- ]
-});
-
-const BarGroup = ({ child }) => Widget.Box({
- className: 'bar-group-margin bar-sides',
- children: [
- Widget.Box({
- className: `bar-group${userOptions.appearance.borderless ? '-borderless' : ''} bar-group-standalone bar-group-pad-system`,
- children: [child],
- }),
- ]
-});
-const BatteryModule = () => Stack({
- transition: 'slide_up_down',
- transitionDuration: userOptions.animations.durationLarge,
- children: {
- 'laptop': Box({
- className: 'spacing-h-4', children: [
- BarGroup({ child: Utilities() }),
- BarGroup({ child: BarBattery() }),
- ]
- }),
- 'desktop': BarGroup({
- child: Box({
- hexpand: true,
- hpack: 'center',
- className: 'spacing-h-4 txt-onSurfaceVariant',
- children: [
- MaterialIcon('device_thermostat', 'small'),
- Label({
- label: 'Weather',
- })
- ],
- setup: (self) => self.poll(900000, async (self) => {
- const WEATHER_CACHE_PATH = WEATHER_CACHE_FOLDER + '/wttr.in.txt';
- const updateWeatherForCity = (city) => execAsync(`curl https://wttr.in/${city.replace(/ /g, '%20')}?format=j1`)
- .then(output => {
- const weather = JSON.parse(output);
- Utils.writeFile(JSON.stringify(weather), WEATHER_CACHE_PATH)
- .catch(print);
- const weatherCode = weather.current_condition[0].weatherCode;
- const weatherDesc = weather.current_condition[0].weatherDesc[0].value;
- const temperature = weather.current_condition[0][`temp_${userOptions.weather.preferredUnit}`];
- const feelsLike = weather.current_condition[0][`FeelsLike${userOptions.weather.preferredUnit}`];
- const weatherSymbol = WEATHER_SYMBOL[WWO_CODE[weatherCode]];
- self.children[0].label = weatherSymbol;
- self.children[1].label = `${temperature}°${userOptions.weather.preferredUnit} • ${getString('Feels like')} ${feelsLike}°${userOptions.weather.preferredUnit}`;
- self.tooltipText = weatherDesc;
- }).catch((err) => {
- try { // Read from cache
- const weather = JSON.parse(
- Utils.readFile(WEATHER_CACHE_PATH)
- );
- const weatherCode = weather.current_condition[0].weatherCode;
- const weatherDesc = weather.current_condition[0].weatherDesc[0].value;
- const temperature = weather.current_condition[0][`temp_${userOptions.weather.preferredUnit}`];
- const feelsLike = weather.current_condition[0][`FeelsLike${userOptions.weather.preferredUnit}`];
- const weatherSymbol = WEATHER_SYMBOL[WWO_CODE[weatherCode]];
- self.children[0].label = weatherSymbol;
- self.children[1].label = `${temperature}°${userOptions.weather.preferredUnit} • ${getString('Feels like')} ${feelsLike}°${userOptions.weather.preferredUnit}`;
- self.tooltipText = weatherDesc;
- } catch (err) {
- print(err);
- }
- });
- if (userOptions.weather.city != '' && userOptions.weather.city != null) {
- updateWeatherForCity(userOptions.weather.city.replace(/ /g, '%20'));
- }
- else {
- Utils.execAsync('curl ipinfo.io')
- .then(output => {
- return JSON.parse(output)['city'].toLowerCase();
- })
- .then(updateWeatherForCity)
- .catch(print)
- }
- }),
- })
- }),
- },
- setup: (stack) => Utils.timeout(10, () => {
- if (!Battery.available) stack.shown = 'desktop';
- else stack.shown = 'laptop';
- })
-})
-
-const switchToRelativeWorkspace = async (self, num) => {
- try {
- const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
- Hyprland.messageAsync(`dispatch workspace r${num > 0 ? '+' : ''}${num}`).catch(print);
- } catch {
- execAsync([`${App.configDir}/scripts/sway/swayToRelativeWs.sh`, `${num}`]).catch(print);
- }
-}
-
-export default () => Widget.EventBox({
- onScrollUp: (self) => switchToRelativeWorkspace(self, -1),
- onScrollDown: (self) => switchToRelativeWorkspace(self, +1),
- onPrimaryClick: () => App.toggleWindow('sideright'),
- child: Widget.Box({
- className: 'spacing-h-4',
- children: [
- BarGroup({ child: BarClock() }),
- BatteryModule(),
- ]
- })
-});
diff --git a/.config/ags/modules/bar/normal/tray.js b/.config/ags/modules/bar/normal/tray.js
deleted file mode 100644
index d568bc769..000000000
--- a/.config/ags/modules/bar/normal/tray.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import SystemTray from 'resource:///com/github/Aylur/ags/service/systemtray.js';
-const { Box, Icon, Button, Revealer } = Widget;
-const { Gravity } = imports.gi.Gdk;
-
-const SysTrayItem = (item) => item.id !== null ? Button({
- className: 'bar-systray-item',
- child: Icon({ hpack: 'center' }).bind('icon', item, 'icon'),
- setup: (self) => self
- .hook(item, (self) => self.tooltipMarkup = item['tooltip-markup'])
- ,
- onPrimaryClick: (_, event) => item.activate(event),
- onSecondaryClick: (btn, event) => item.menu.popup_at_widget(btn, Gravity.SOUTH, Gravity.NORTH, null),
-}) : null;
-
-export const Tray = (props = {}) => {
- const trayContent = Box({
- className: 'margin-right-5 spacing-h-15',
- setup: (self) => self
- .hook(SystemTray, (self) => {
- self.children = SystemTray.items.map(SysTrayItem);
- self.show_all();
- })
- ,
- });
- const trayRevealer = Widget.Revealer({
- revealChild: true,
- transition: 'slide_left',
- transitionDuration: userOptions.animations.durationLarge,
- child: trayContent,
- });
- return Box({
- ...props,
- children: [trayRevealer],
- });
-}
diff --git a/.config/ags/modules/bar/normal/workspaces_hyprland.js b/.config/ags/modules/bar/normal/workspaces_hyprland.js
deleted file mode 100644
index 5bc24180e..000000000
--- a/.config/ags/modules/bar/normal/workspaces_hyprland.js
+++ /dev/null
@@ -1,224 +0,0 @@
-const { GLib, Gdk, Gtk } = imports.gi;
-const Lang = imports.lang;
-const Cairo = imports.cairo;
-const Pango = imports.gi.Pango;
-const PangoCairo = imports.gi.PangoCairo;
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-const { Box, DrawingArea, EventBox } = Widget;
-import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
-
-const dummyWs = Box({ className: 'bar-ws' }); // Not shown. Only for getting size props
-const dummyActiveWs = Box({ className: 'bar-ws bar-ws-active' }); // Not shown. Only for getting size props
-const dummyOccupiedWs = Box({ className: 'bar-ws bar-ws-occupied' }); // Not shown. Only for getting size props
-
-const mix = (value1, value2, perc) => {
- return value1 * perc + value2 * (1 - perc);
-}
-
-const getFontWeightName = (weight) => {
- switch (weight) {
- case Pango.Weight.ULTRA_LIGHT:
- return 'UltraLight';
- case Pango.Weight.LIGHT:
- return 'Light';
- case Pango.Weight.NORMAL:
- return 'Normal';
- case Pango.Weight.BOLD:
- return 'Bold';
- case Pango.Weight.ULTRA_BOLD:
- return 'UltraBold';
- case Pango.Weight.HEAVY:
- return 'Heavy';
- default:
- return 'Normal';
- }
-}
-
-// Font size = workspace id
-const WorkspaceContents = (count = 10) => {
- return DrawingArea({
- className: 'bar-ws-container',
- attribute: {
- initialized: false,
- workspaceMask: 0,
- workspaceGroup: 0,
- updateMask: (self) => {
- const offset = Math.floor((Hyprland.active.workspace.id - 1) / count) * userOptions.workspaces.shown;
- // if (self.attribute.initialized) return; // We only need this to run once
- const workspaces = Hyprland.workspaces;
- let workspaceMask = 0;
- for (let i = 0; i < workspaces.length; i++) {
- const ws = workspaces[i];
- if (ws.id <= offset || ws.id > offset + count) continue; // Out of range, ignore
- if (workspaces[i].windows > 0)
- workspaceMask |= (1 << (ws.id - offset));
- }
- // console.log('Mask:', workspaceMask.toString(2));
- self.attribute.workspaceMask = workspaceMask;
- // self.attribute.initialized = true;
- self.queue_draw();
- },
- toggleMask: (self, occupied, name) => {
- if (occupied) self.attribute.workspaceMask |= (1 << parseInt(name));
- else self.attribute.workspaceMask &= ~(1 << parseInt(name));
- self.queue_draw();
- },
- },
- setup: (area) => area
- .hook(Hyprland.active.workspace, (self) => {
- self.setCss(`font-size: ${(Hyprland.active.workspace.id - 1) % count + 1}px;`);
- const previousGroup = self.attribute.workspaceGroup;
- const currentGroup = Math.floor((Hyprland.active.workspace.id - 1) / count);
- if (currentGroup !== previousGroup) {
- self.attribute.updateMask(self);
- self.attribute.workspaceGroup = currentGroup;
- }
- })
- .hook(Hyprland, (self) => self.attribute.updateMask(self), 'notify::workspaces')
- .on('draw', Lang.bind(area, (area, cr) => {
- const offset = Math.floor((Hyprland.active.workspace.id - 1) / count) * userOptions.workspaces.shown;
-
- const allocation = area.get_allocation();
- const { width, height } = allocation;
-
- const workspaceStyleContext = dummyWs.get_style_context();
- const workspaceDiameter = workspaceStyleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
- const workspaceRadius = workspaceDiameter / 2;
- const workspaceFontSize = workspaceStyleContext.get_property('font-size', Gtk.StateFlags.NORMAL) / 4 * 3;
- const workspaceFontFamily = workspaceStyleContext.get_property('font-family', Gtk.StateFlags.NORMAL);
- const workspaceFontWeight = workspaceStyleContext.get_property('font-weight', Gtk.StateFlags.NORMAL);
- const wsbg = workspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
- const wsfg = workspaceStyleContext.get_property('color', Gtk.StateFlags.NORMAL);
-
- const occupiedWorkspaceStyleContext = dummyOccupiedWs.get_style_context();
- const occupiedbg = occupiedWorkspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
- const occupiedfg = occupiedWorkspaceStyleContext.get_property('color', Gtk.StateFlags.NORMAL);
-
- const activeWorkspaceStyleContext = dummyActiveWs.get_style_context();
- const activebg = activeWorkspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
- const activefg = activeWorkspaceStyleContext.get_property('color', Gtk.StateFlags.NORMAL);
- area.set_size_request(workspaceDiameter * count, -1);
- const widgetStyleContext = area.get_style_context();
- const activeWs = widgetStyleContext.get_property('font-size', Gtk.StateFlags.NORMAL);
-
- const activeWsCenterX = -(workspaceDiameter / 2) + (workspaceDiameter * activeWs);
- const activeWsCenterY = height / 2;
-
- // Font
- const layout = PangoCairo.create_layout(cr);
- const fontDesc = Pango.font_description_from_string(`${workspaceFontFamily[0]} ${getFontWeightName(workspaceFontWeight)} ${workspaceFontSize}`);
- layout.set_font_description(fontDesc);
- cr.setAntialias(Cairo.Antialias.BEST);
- // Get kinda min radius for number indicators
- layout.set_text("0".repeat(count.toString().length), -1);
- const [layoutWidth, layoutHeight] = layout.get_pixel_size();
- const indicatorRadius = Math.max(layoutWidth, layoutHeight) / 2 * 1.15; // smaller than sqrt(2)*radius
- const indicatorGap = workspaceRadius - indicatorRadius;
-
- for (let i = 1; i <= count; i++) {
- if (area.attribute.workspaceMask & (1 << i)) {
- // Draw bg highlight
- cr.setSourceRGBA(occupiedbg.red, occupiedbg.green, occupiedbg.blue, occupiedbg.alpha);
- const wsCenterX = -(workspaceRadius) + (workspaceDiameter * i);
- const wsCenterY = height / 2;
- if (!(area.attribute.workspaceMask & (1 << (i - 1)))) { // Left
- cr.arc(wsCenterX, wsCenterY, workspaceRadius, 0.5 * Math.PI, 1.5 * Math.PI);
- cr.fill();
- }
- else {
- cr.rectangle(wsCenterX - workspaceRadius, wsCenterY - workspaceRadius, workspaceRadius, workspaceRadius * 2)
- cr.fill();
- }
- if (!(area.attribute.workspaceMask & (1 << (i + 1)))) { // Right
- cr.arc(wsCenterX, wsCenterY, workspaceRadius, -0.5 * Math.PI, 0.5 * Math.PI);
- cr.fill();
- }
- else {
- cr.rectangle(wsCenterX, wsCenterY - workspaceRadius, workspaceRadius, workspaceRadius * 2)
- cr.fill();
- }
- }
- }
-
- // Draw active ws
- cr.setSourceRGBA(activebg.red, activebg.green, activebg.blue, activebg.alpha);
- cr.arc(activeWsCenterX, activeWsCenterY, indicatorRadius, 0, 2 * Math.PI);
- cr.fill();
-
- // Draw workspace numbers
- for (let i = 1; i <= count; i++) {
- const inactivecolors = area.attribute.workspaceMask & (1 << i) ? occupiedfg : wsfg;
- if (i == activeWs) {
- cr.setSourceRGBA(activefg.red, activefg.green, activefg.blue, activefg.alpha);
- }
- // Moving to
- else if ((i == Math.floor(activeWs) && Hyprland.active.workspace.id < activeWs) || (i == Math.ceil(activeWs) && Hyprland.active.workspace.id > activeWs)) {
- cr.setSourceRGBA(mix(activefg.red, inactivecolors.red, 1 - Math.abs(activeWs - i)), mix(activefg.green, inactivecolors.green, 1 - Math.abs(activeWs - i)), mix(activefg.blue, inactivecolors.blue, 1 - Math.abs(activeWs - i)), activefg.alpha);
- }
- // Moving from
- else if ((i == Math.floor(activeWs) && Hyprland.active.workspace.id > activeWs) || (i == Math.ceil(activeWs) && Hyprland.active.workspace.id < activeWs)) {
- cr.setSourceRGBA(mix(activefg.red, inactivecolors.red, 1 - Math.abs(activeWs - i)), mix(activefg.green, inactivecolors.green, 1 - Math.abs(activeWs - i)), mix(activefg.blue, inactivecolors.blue, 1 - Math.abs(activeWs - i)), activefg.alpha);
- }
- // Inactive
- else
- cr.setSourceRGBA(inactivecolors.red, inactivecolors.green, inactivecolors.blue, inactivecolors.alpha);
-
- layout.set_text(`${i + offset}`, -1);
- const [layoutWidth, layoutHeight] = layout.get_pixel_size();
- const x = -workspaceRadius + (workspaceDiameter * i) - (layoutWidth / 2);
- const y = (height - layoutHeight) / 2;
- cr.moveTo(x, y);
- PangoCairo.show_layout(cr, layout);
- cr.stroke();
- }
- }))
- ,
- })
-}
-
-export default () => EventBox({
- onScrollUp: () => Hyprland.messageAsync(`dispatch workspace r-1`).catch(print),
- onScrollDown: () => Hyprland.messageAsync(`dispatch workspace r+1`).catch(print),
- onMiddleClick: () => toggleWindowOnAllMonitors('osk'),
- onSecondaryClick: () => App.toggleWindow('overview'),
- attribute: {
- clicked: false,
- ws_group: 0,
- },
- child: Box({
- homogeneous: true,
- className: 'bar-group-margin',
- children: [Box({
- className: `bar-group${userOptions.appearance.borderless ? '-borderless' : ''} bar-group-standalone bar-group-pad`,
- css: 'min-width: 2px;',
- children: [WorkspaceContents(userOptions.workspaces.shown)],
- })]
- }),
- setup: (self) => {
- self.add_events(Gdk.EventMask.POINTER_MOTION_MASK);
- self.on('motion-notify-event', (self, event) => {
- if (!self.attribute.clicked) return;
- const [_, cursorX, cursorY] = event.get_coords();
- const widgetWidth = self.get_allocation().width;
- const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth);
- Utils.execAsync([`${App.configDir}/scripts/hyprland/workspace_action.sh`, 'workspace', `${wsId}`])
- .catch(print);
- })
- self.on('button-press-event', (self, event) => {
- if (event.get_button()[1] === 1) {
- self.attribute.clicked = true;
- const [_, cursorX, cursorY] = event.get_coords();
- const widgetWidth = self.get_allocation().width;
- const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth);
- Utils.execAsync([`${App.configDir}/scripts/hyprland/workspace_action.sh`, 'workspace', `${wsId}`])
- .catch(print);
- }
- else if (event.get_button()[1] === 8) {
- Hyprland.messageAsync(`dispatch togglespecialworkspace`).catch(print);
- }
- })
- self.on('button-release-event', (self) => self.attribute.clicked = false);
- }
-})
diff --git a/.config/ags/modules/bar/normal/workspaces_sway.js b/.config/ags/modules/bar/normal/workspaces_sway.js
deleted file mode 100644
index e883ece55..000000000
--- a/.config/ags/modules/bar/normal/workspaces_sway.js
+++ /dev/null
@@ -1,183 +0,0 @@
-const { GLib, Gdk, Gtk } = imports.gi;
-const Lang = imports.lang;
-const Cairo = imports.cairo;
-const Pango = imports.gi.Pango;
-const PangoCairo = imports.gi.PangoCairo;
-import Widget from "resource:///com/github/Aylur/ags/widget.js";
-import Sway from "../../../services/sway.js";
-import * as Utils from "resource:///com/github/Aylur/ags/utils.js";
-const { execAsync, exec } = Utils;
-const { Box, DrawingArea, EventBox } = Widget;
-
-const dummyWs = Box({ className: 'bar-ws' }); // Not shown. Only for getting size props
-const dummyActiveWs = Box({ className: 'bar-ws bar-ws-active' }); // Not shown. Only for getting size props
-const dummyOccupiedWs = Box({ className: 'bar-ws bar-ws-occupied' }); // Not shown. Only for getting size props
-
-const switchToWorkspace = (arg) => Utils.execAsync(`swaymsg workspace ${arg}`).catch(print);
-const switchToRelativeWorkspace = (self, num) =>
- execAsync([`${App.configDir}/scripts/sway/swayToRelativeWs.sh`, `${num}`]).catch(print);
-
-const WorkspaceContents = (count = 10) => {
- return DrawingArea({
- css: `transition: 90ms cubic-bezier(0.1, 1, 0, 1);`,
- attribute: {
- initialized: false,
- workspaceMask: 0,
- updateMask: (self) => {
- if (self.attribute.initialized) return; // We only need this to run once
- const workspaces = Sway.workspaces;
- let workspaceMask = 0;
- // console.log('----------------')
- for (let i = 0; i < workspaces.length; i++) {
- const ws = workspaces[i];
- // console.log(ws.name, ',', ws.num);
- if (!Number(ws.name)) return;
- const id = Number(ws.name);
- if (id <= 0) continue; // Ignore scratchpads
- if (id > count) return; // Not rendered
- if (workspaces[i].windows > 0) {
- workspaceMask |= (1 << id);
- }
- }
- self.attribute.workspaceMask = workspaceMask;
- self.attribute.initialized = true;
- },
- toggleMask: (self, occupied, name) => {
- if (occupied) self.attribute.workspaceMask |= (1 << parseInt(name));
- else self.attribute.workspaceMask &= ~(1 << parseInt(name));
- },
- },
- setup: (area) => area
- .hook(Sway.active.workspace, (area) => {
- area.setCss(`font-size: ${Sway.active.workspace.name}px;`)
- })
- .hook(Sway, (self) => self.attribute.updateMask(self), 'notify::workspaces')
- // .hook(Hyprland, (self, name) => self.attribute.toggleMask(self, true, name), 'workspace-added')
- // .hook(Hyprland, (self, name) => self.attribute.toggleMask(self, false, name), 'workspace-removed')
- .on('draw', Lang.bind(area, (area, cr) => {
- const allocation = area.get_allocation();
- const { width, height } = allocation;
-
- const workspaceStyleContext = dummyWs.get_style_context();
- const workspaceDiameter = workspaceStyleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
- const workspaceRadius = workspaceDiameter / 2;
- const workspaceFontSize = workspaceStyleContext.get_property('font-size', Gtk.StateFlags.NORMAL) / 4 * 3;
- const workspaceFontFamily = workspaceStyleContext.get_property('font-family', Gtk.StateFlags.NORMAL);
- const wsbg = workspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
- const wsfg = workspaceStyleContext.get_property('color', Gtk.StateFlags.NORMAL);
-
- const occupiedWorkspaceStyleContext = dummyOccupiedWs.get_style_context();
- const occupiedbg = occupiedWorkspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
- const occupiedfg = occupiedWorkspaceStyleContext.get_property('color', Gtk.StateFlags.NORMAL);
-
- const activeWorkspaceStyleContext = dummyActiveWs.get_style_context();
- const activebg = activeWorkspaceStyleContext.get_property('background-color', Gtk.StateFlags.NORMAL);
- const activefg = activeWorkspaceStyleContext.get_property('color', Gtk.StateFlags.NORMAL);
- area.set_size_request(workspaceDiameter * count, -1);
- const widgetStyleContext = area.get_style_context();
- const activeWs = widgetStyleContext.get_property('font-size', Gtk.StateFlags.NORMAL);
-
- const activeWsCenterX = -(workspaceDiameter / 2) + (workspaceDiameter * activeWs);
- const activeWsCenterY = height / 2;
-
- // Font
- const layout = PangoCairo.create_layout(cr);
- const fontDesc = Pango.font_description_from_string(`${workspaceFontFamily[0]} ${workspaceFontSize}`);
- layout.set_font_description(fontDesc);
- cr.setAntialias(Cairo.Antialias.BEST);
- // Get kinda min radius for number indicators
- layout.set_text("0".repeat(count.toString().length), -1);
- const [layoutWidth, layoutHeight] = layout.get_pixel_size();
- const indicatorRadius = Math.max(layoutWidth, layoutHeight) / 2 * 1.2; // a bit smaller than sqrt(2)*radius
- const indicatorGap = workspaceRadius - indicatorRadius;
-
- // Draw workspace numbers
- for (let i = 1; i <= count; i++) {
- if (area.attribute.workspaceMask & (1 << i)) {
- // Draw bg highlight
- cr.setSourceRGBA(occupiedbg.red, occupiedbg.green, occupiedbg.blue, occupiedbg.alpha);
- const wsCenterX = -(workspaceRadius) + (workspaceDiameter * i);
- const wsCenterY = height / 2;
- if (!(area.attribute.workspaceMask & (1 << (i - 1)))) { // Left
- cr.arc(wsCenterX, wsCenterY, workspaceRadius, 0.5 * Math.PI, 1.5 * Math.PI);
- cr.fill();
- }
- else {
- cr.rectangle(wsCenterX - workspaceRadius, wsCenterY - workspaceRadius, workspaceRadius, workspaceRadius * 2)
- cr.fill();
- }
- if (!(area.attribute.workspaceMask & (1 << (i + 1)))) { // Right
- cr.arc(wsCenterX, wsCenterY, workspaceRadius, -0.5 * Math.PI, 0.5 * Math.PI);
- cr.fill();
- }
- else {
- cr.rectangle(wsCenterX, wsCenterY - workspaceRadius, workspaceRadius, workspaceRadius * 2)
- cr.fill();
- }
-
- // Set color for text
- cr.setSourceRGBA(occupiedfg.red, occupiedfg.green, occupiedfg.blue, occupiedfg.alpha);
- }
- else
- cr.setSourceRGBA(wsfg.red, wsfg.green, wsfg.blue, wsfg.alpha);
- layout.set_text(`${i}`, -1);
- const [layoutWidth, layoutHeight] = layout.get_pixel_size();
- const x = -workspaceRadius + (workspaceDiameter * i) - (layoutWidth / 2);
- const y = (height - layoutHeight) / 2;
- cr.moveTo(x, y);
- // cr.showText(text);
- PangoCairo.show_layout(cr, layout);
- cr.stroke();
- }
-
- // Draw active ws
- // base
- cr.setSourceRGBA(activebg.red, activebg.green, activebg.blue, activebg.alpha);
- cr.arc(activeWsCenterX, activeWsCenterY, indicatorRadius, 0, 2 * Math.PI);
- cr.fill();
- // inner decor
- cr.setSourceRGBA(activefg.red, activefg.green, activefg.blue, activefg.alpha);
- cr.arc(activeWsCenterX, activeWsCenterY, indicatorRadius * 0.2, 0, 2 * Math.PI);
- cr.fill();
- }))
- ,
- })
-}
-
-export default () => EventBox({
- onScrollUp: (self) => switchToRelativeWorkspace(self, -1),
- onScrollDown: (self) => switchToRelativeWorkspace(self, +1),
- onMiddleClick: () => toggleWindowOnAllMonitors('osk'),
- onSecondaryClick: () => App.toggleWindow('overview'),
- attribute: { clicked: false },
- child: Box({
- homogeneous: true,
- className: 'bar-group-margin',
- children: [Box({
- className: `bar-group${userOptions.appearance.borderless ? '-borderless' : ''} bar-group-standalone bar-group-pad`,
- css: 'min-width: 2px;',
- children: [
- WorkspaceContents(10),
- ]
- })]
- }),
- setup: (self) => {
- self.add_events(Gdk.EventMask.POINTER_MOTION_MASK);
- self.on('motion-notify-event', (self, event) => {
- if (!self.attribute.clicked) return;
- const [_, cursorX, cursorY] = event.get_coords();
- const widgetWidth = self.get_allocation().width;
- const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth);
- switchToWorkspace(wsId);
- })
- self.on('button-press-event', (self, event) => {
- if (!(event.get_button()[1] === 1)) return; // We're only interested in left-click here
- self.attribute.clicked = true;
- const [_, cursorX, cursorY] = event.get_coords();
- const widgetWidth = self.get_allocation().width;
- const wsId = Math.ceil(cursorX * userOptions.workspaces.shown / widgetWidth);
- switchToWorkspace(wsId);
- })
- self.on('button-release-event', (self) => self.attribute.clicked = false);
- }
-});
diff --git a/.config/ags/modules/cheatsheet/data_keybinds.js b/.config/ags/modules/cheatsheet/data_keybinds.js
deleted file mode 100644
index 5631c4983..000000000
--- a/.config/ags/modules/cheatsheet/data_keybinds.js
+++ /dev/null
@@ -1,122 +0,0 @@
-export const keybindList = [[
- {
- "icon": "pin_drop",
- "name": "Workspaces: navigation",
- "binds": [
- { "keys": ["", "+", "#"], "action": "Go to workspace #" },
- { "keys": ["", "+", "S"], "action": "Toggle special workspace" },
- { "keys": ["", "+", "(Scroll ↑↓)"], "action": "Go to workspace -1/+1" },
- { "keys": ["Ctrl", "", "+", "←"], "action": "Go to workspace on the left" },
- { "keys": ["Ctrl", "", "+", "→"], "action": "Go to workspace on the right" },
- { "keys": ["", "+", "PageUp"], "action": "Go to workspace on the left" },
- { "keys": ["", "+", "PageDown"], "action": "Go to workspace on the right" }
- ],
- "id": 1
- },
- {
- "icon": "overview_key",
- "name": "Workspaces: management",
- "binds": [
- { "keys": ["", "Alt", "+", "#"], "action": "Move window to workspace #" },
- { "keys": ["", "Alt", "+", "S"], "action": "Move window to special workspace" },
- { "keys": ["", "Alt", "+", "PageUp"], "action": "Move window to workspace on the left" },
- { "keys": ["", "Alt", "+", "PageDown"], "action": "Move window to workspace on the right" }
- ],
- "id": 2
- },
- {
- "icon": "move_group",
- "name": "Windows",
- "binds": [
- { "keys": ["", "+", "←↑→↓"], "action": "Focus window in direction" },
- { "keys": ["", "Shift", "+", "←↑→↓"], "action": "Swap window in direction" },
- { "keys": ["", "+", ";"], "action": "Split ratio -" },
- { "keys": ["", "+", "'"], "action": "Split ratio +" },
- { "keys": ["", "+", "Lmb"], "action": "Move window" },
- { "keys": ["", "+", "Rmb"], "action": "Resize window" },
- { "keys": ["", "Alt", "+", "Space"], "action": "Float window" },
- { "keys": ["", "+", "F"], "action": "Fullscreen" },
- { "keys": ["", "Alt", "+", "F"], "action": "Fake fullscreen" }
- ],
- "id": 3
- }
-],
-[
- {
- "icon": "widgets",
- "name": "Widgets (AGS)",
- "binds": [
- { "keys": ["", "OR", "", "+", "Tab"], "action": "Toggle overview/launcher" },
- { "keys": ["Ctrl", "", "+", "R"], "action": "Restart AGS" },
- { "keys": ["", "+", "/"], "action": "Toggle this cheatsheet" },
- { "keys": ["", "+", "N"], "action": "Toggle system sidebar" },
- { "keys": ["", "+", "B", "OR", "", "+", "O"], "action": "Toggle utilities sidebar" },
- { "keys": ["", "+", "K"], "action": "Toggle virtual keyboard" },
- { "keys": ["Ctrl", "Alt", "+", "Del"], "action": "Power/Session menu" },
-
- { "keys": ["Esc"], "action": "Exit a window" },
- { "keys": ["rightCtrl"], "action": "Dismiss/close sidebar" },
-
- { "keys": ["Ctrl", "", "+", "T"], "action": "Change wallpaper+colorscheme" },
-
- // { "keys": ["", "+", "B"], "action": "Toggle left sidebar" },
- // { "keys": ["", "+", "N"], "action": "Toggle right sidebar" },
- // { "keys": ["", "+", "G"], "action": "Toggle volume mixer" },
- // { "keys": ["", "+", "M"], "action": "Toggle useless audio visualizer" },
- // { "keys": ["(right)Ctrl"], "action": "Dismiss notification & close menus" }
- ],
- "id": 4
- },
- {
- "icon": "construction",
- "name": "Utilities",
- "binds": [
- { "keys": ["PrtSc"], "action": "Screenshot >> clipboard" },
- { "keys": ["Ctrl", "PrtSc"], "action": "Screenshot >> file + clipboard" },
- { "keys": ["", "Shift", "+", "S"], "action": "Screen snip >> clipboard" },
- { "keys": ["", "Shift", "+", "T"], "action": "Image to text >> clipboard" },
- { "keys": ["", "Shift", "+", "C"], "action": "Color picker" },
- { "keys": ["", "Alt", "+", "R"], "action": "Record region" },
- { "keys": ["Ctrl", "Alt", "+", "R"], "action": "Record region with sound" },
- { "keys": ["", "Shift", "Alt", "+", "R"], "action": "Record screen with sound" }
- ],
- "id": 5
- },
-],
-[
- {
- "icon": "apps",
- "name": "Apps",
- "binds": [
- { "keys": ["", "+", "T"], "action": "Launch terminal: foot" },
- { "keys": ["", "+", "W"], "action": "Launch browser: Firefox" },
- { "keys": ["", "+", "C"], "action": "Launch editor: vscode" },
- { "keys": ["", "+", "X"], "action": "Launch editor: GNOME Text Editor" },
- { "keys": ["", "+", "I"], "action": "Launch settings: GNOME Control center" }
- ],
- "id": 6
- },
- {
- "icon": "keyboard",
- "name": "Typing",
- "binds": [
- { "keys": ["", "+", "V"], "action": "Clipboard history >> clipboard" },
- { "keys": ["", "+", "."], "action": "Emoji picker >> clipboard" },
- ],
- "id": 7
- },
- {
- "icon": "terminal",
- "name": "Launcher actions",
- "binds": [
- { "keys": [">raw"], "action": "Toggle mouse acceleration" },
- { "keys": [">img"], "action": "Select wallpaper and generate colorscheme" },
- { "keys": [">light"], "action": "Switch to light theme" },
- { "keys": [">dark"], "action": "Switch to dark theme" },
- { "keys": [">badapple"], "action": "Apply black n' white colorscheme" },
- { "keys": [">color"], "action": "Pick acccent color" },
- { "keys": [">todo"], "action": "Type something after that to add a To-do item" },
- ],
- "id": 8
- }
-]];
diff --git a/.config/ags/modules/cheatsheet/data_periodictable.js b/.config/ags/modules/cheatsheet/data_periodictable.js
deleted file mode 100644
index f7f47a0e0..000000000
--- a/.config/ags/modules/cheatsheet/data_periodictable.js
+++ /dev/null
@@ -1,195 +0,0 @@
-export const periodicTable = [
- [
- { name: 'Hydrogen', symbol: 'H', number: 1, weight: 1.01, type: 'nonmetal' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: 'Helium', symbol: 'He', number: 2, weight: 4.00, type: 'noblegas' },
- ],
- [
- { name: 'Lithium', symbol: 'Li', number: 3, weight: 6.94, type: 'metal' },
- { name: 'Beryllium', symbol: 'Be', number: 4, weight: 9.01, type: 'metal' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: 'Boron', symbol: 'B', number: 5, weight: 10.81, type: 'nonmetal' },
- { name: 'Carbon', symbol: 'C', number: 6, weight: 12.01, type: 'nonmetal' },
- { name: 'Nitrogen', symbol: 'N', number: 7, weight: 14.01, type: 'nonmetal' },
- { name: 'Oxygen', symbol: 'O', number: 8, weight: 16, type: 'nonmetal' },
- { name: 'Fluorine', symbol: 'F', number: 9, weight: 19, type: 'nonmetal' },
- { name: 'Neon', symbol: 'Ne', number: 10, weight: 20.18, type: 'noblegas' },
-
-
- ],
- [
- { name: 'Sodium', symbol: 'Na', number: 11, weight: 22.99, type: 'metal' },
- { name: 'Magnesium', symbol: 'Mg', number: 12, weight: 24.31, type: 'metal' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: 'Aluminum', symbol: 'Al', number: 13, weight: 26.98, type: 'metal' },
- { name: 'Silicon', symbol: 'Si', number: 14, weight: 28.09, type: 'nonmetal' },
- { name: 'Phosphorus', symbol: 'P', number: 15, weight: 30.97, type: 'nonmetal' },
- { name: 'Sulfur', symbol: 'S', number: 16, weight: 32.07, type: 'nonmetal' },
- { name: 'Chlorine', symbol: 'Cl', number: 17, weight: 35.45, type: 'nonmetal' },
- { name: 'Argon', symbol: 'Ar', number: 18, weight: 39.95, type: 'noblegas' },
- ],
- [
- { name: 'Potassium', symbol: 'K', number: 19, weight: 39.098, type: 'metal' },
- { name: 'Calcium', symbol: 'Ca', number: 20, weight: 40.078, type: 'metal' },
- { name: 'Scandium', symbol: 'Sc', number: 21, weight: 44.956, type: 'metal' },
- { name: 'Titanium', symbol: 'Ti', number: 22, weight: 47.87, type: 'metal' },
- { name: 'Vanadium', symbol: 'V', number: 23, weight: 50.94, type: 'metal' },
- { name: 'Chromium', symbol: 'Cr', number: 24, weight: 52, type: 'metal'/*, icon: 'chromium-browser'*/ },
- { name: 'Manganese', symbol: 'Mn', number: 25, weight: 54.94, type: 'metal' },
- { name: 'Iron', symbol: 'Fe', number: 26, weight: 55.85, type: 'metal' },
- { name: 'Cobalt', symbol: 'Co', number: 27, weight: 58.93, type: 'metal' },
- { name: 'Nickel', symbol: 'Ni', number: 28, weight: 58.69, type: 'metal' },
- { name: 'Copper', symbol: 'Cu', number: 29, weight: 63.55, type: 'metal' },
- { name: 'Zinc', symbol: 'Zn', number: 30, weight: 65.38, type: 'metal' },
- { name: 'Gallium', symbol: 'Ga', number: 31, weight: 69.72, type: 'metal' },
- { name: 'Germanium', symbol: 'Ge', number: 32, weight: 72.63, type: 'metal' },
- { name: 'Arsenic', symbol: 'As', number: 33, weight: 74.92, type: 'nonmetal' },
- { name: 'Selenium', symbol: 'Se', number: 34, weight: 78.96, type: 'nonmetal' },
- { name: 'Bromine', symbol: 'Br', number: 35, weight: 79.904, type: 'nonmetal' },
- { name: 'Krypton', symbol: 'Kr', number: 36, weight: 83.8, type: 'noblegas' },
- ],
- [
- { name: 'Rubidium', symbol: 'Rb', number: 37, weight: 85.47, type: 'metal' },
- { name: 'Strontium', symbol: 'Sr', number: 38, weight: 87.62, type: 'metal' },
- { name: 'Yttrium', symbol: 'Y', number: 39, weight: 88.91, type: 'metal' },
- { name: 'Zirconium', symbol: 'Zr', number: 40, weight: 91.22, type: 'metal' },
- { name: 'Niobium', symbol: 'Nb', number: 41, weight: 92.91, type: 'metal' },
- { name: 'Molybdenum', symbol: 'Mo', number: 42, weight: 95.94, type: 'metal' },
- { name: 'Technetium', symbol: 'Tc', number: 43, weight: 98, type: 'metal' },
- { name: 'Ruthenium', symbol: 'Ru', number: 44, weight: 101.07, type: 'metal' },
- { name: 'Rhodium', symbol: 'Rh', number: 45, weight: 102.91, type: 'metal' },
- { name: 'Palladium', symbol: 'Pd', number: 46, weight: 106.42, type: 'metal' },
- { name: 'Silver', symbol: 'Ag', number: 47, weight: 107.87, type: 'metal' },
- { name: 'Cadmium', symbol: 'Cd', number: 48, weight: 112.41, type: 'metal' },
- { name: 'Indium', symbol: 'In', number: 49, weight: 114.82, type: 'metal' },
- { name: 'Tin', symbol: 'Sn', number: 50, weight: 118.71, type: 'metal' },
- { name: 'Antimony', symbol: 'Sb', number: 51, weight: 121.76, type: 'metal' },
- { name: 'Tellurium', symbol: 'Te', number: 52, weight: 127.6, type: 'nonmetal' },
- { name: 'Iodine', symbol: 'I', number: 53, weight: 126.9, type: 'nonmetal' },
- { name: 'Xenon', symbol: 'Xe', number: 54, weight: 131.29, type: 'noblegas' },
- ],
- [
- { name: 'Cesium', symbol: 'Cs', number: 55, weight: 132.91, type: 'metal' },
- { name: 'Barium', symbol: 'Ba', number: 56, weight: 137.33, type: 'metal' },
- { name: 'Lanthanum', symbol: 'La', number: 57, weight: 138.91, type: 'lanthanum' },
- { name: 'Hafnium', symbol: 'Hf', number: 72, weight: 178.49, type: 'metal' },
- { name: 'Tantalum', symbol: 'Ta', number: 73, weight: 180.95, type: 'metal' },
- { name: 'Tungsten', symbol: 'W', number: 74, weight: 183.84, type: 'metal' },
- { name: 'Rhenium', symbol: 'Re', number: 75, weight: 186.21, type: 'metal' },
- { name: 'Osmium', symbol: 'Os', number: 76, weight: 190.23, type: 'metal' },
- { name: 'Iridium', symbol: 'Ir', number: 77, weight: 192.22, type: 'metal' },
- { name: 'Platinum', symbol: 'Pt', number: 78, weight: 195.09, type: 'metal' },
- { name: 'Gold', symbol: 'Au', number: 79, weight: 196.97, type: 'metal' },
- { name: 'Mercury', symbol: 'Hg', number: 80, weight: 200.59, type: 'metal' },
- { name: 'Thallium', symbol: 'Tl', number: 81, weight: 204.38, type: 'metal' },
- { name: 'Lead', symbol: 'Pb', number: 82, weight: 207.2, type: 'metal' },
- { name: 'Bismuth', symbol: 'Bi', number: 83, weight: 208.98, type: 'metal' },
- { name: 'Polonium', symbol: 'Po', number: 84, weight: 209, type: 'metal' },
- { name: 'Astatine', symbol: 'At', number: 85, weight: 210, type: 'nonmetal' },
- { name: 'Radon', symbol: 'Rn', number: 86, weight: 222, type: 'noblegas' },
- ],
- [
- { name: 'Francium', symbol: 'Fr', number: 87, weight: 223, type: 'metal' },
- { name: 'Radium', symbol: 'Ra', number: 88, weight: 226, type: 'metal' },
- { name: 'Actinium', symbol: 'Ac', number: 89, weight: 227, type: 'actinium' },
- { name: 'Rutherfordium', symbol: 'Rf', number: 104, weight: 267, type: 'metal' },
- { name: 'Dubnium', symbol: 'Db', number: 105, weight: 268, type: 'metal' },
- { name: 'Seaborgium', symbol: 'Sg', number: 106, weight: 271, type: 'metal' },
- { name: 'Bohrium', symbol: 'Bh', number: 107, weight: 272, type: 'metal' },
- { name: 'Hassium', symbol: 'Hs', number: 108, weight: 277, type: 'metal' },
- { name: 'Meitnerium', symbol: 'Mt', number: 109, weight: 278, type: 'metal' },
- { name: 'Darmstadtium', symbol: 'Ds', number: 110, weight: 281, type: 'metal' },
- { name: 'Roentgenium', symbol: 'Rg', number: 111, weight: 280, type: 'metal' },
- { name: 'Copernicium', symbol: 'Cn', number: 112, weight: 285, type: 'metal' },
- { name: 'Nihonium', symbol: 'Nh', number: 113, weight: 286, type: 'metal' },
- { name: 'Flerovium', symbol: 'Fl', number: 114, weight: 289, type: 'metal' },
- { name: 'Moscovium', symbol: 'Mc', number: 115, weight: 290, type: 'metal' },
- { name: 'Livermorium', symbol: 'Lv', number: 116, weight: 293, type: 'metal' },
- { name: 'Tennessine', symbol: 'Ts', number: 117, weight: 294, type: 'metal' },
- { name: 'Oganesson', symbol: 'Og', number: 118, weight: 294, type: 'noblegas' },
- ],
-]
-
-export const series = [
- [
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: 'Cerium', symbol: 'Ce', number: 58, weight: 140.12, type: 'lanthanum' },
- { name: 'Praseodymium', symbol: 'Pr', number: 59, weight: 140.91, type: 'lanthanum' },
- { name: 'Neodymium', symbol: 'Nd', number: 60, weight: 144.24, type: 'lanthanum' },
- { name: 'Promethium', symbol: 'Pm', number: 61, weight: 145, type: 'lanthanum' },
- { name: 'Samarium', symbol: 'Sm', number: 62, weight: 150.36, type: 'lanthanum' },
- { name: 'Europium', symbol: 'Eu', number: 63, weight: 151.96, type: 'lanthanum' },
- { name: 'Gadolinium', symbol: 'Gd', number: 64, weight: 157.25, type: 'lanthanum' },
- { name: 'Terbium', symbol: 'Tb', number: 65, weight: 158.93, type: 'lanthanum' },
- { name: 'Dysprosium', symbol: 'Dy', number: 66, weight: 162.5, type: 'lanthanum' },
- { name: 'Holmium', symbol: 'Ho', number: 67, weight: 164.93, type: 'lanthanum' },
- { name: 'Erbium', symbol: 'Er', number: 68, weight: 167.26, type: 'lanthanum' },
- { name: 'Thulium', symbol: 'Tm', number: 69, weight: 168.93, type: 'lanthanum' },
- { name: 'Ytterbium', symbol: 'Yb', number: 70, weight: 173.04, type: 'lanthanum' },
- { name: 'Lutetium', symbol: 'Lu', number: 71, weight: 174.97, type: 'lanthanum' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- ],
- [
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- { name: 'Thorium', symbol: 'Th', number: 90, weight: 232.04, type: 'actinium' },
- { name: 'Protactinium', symbol: 'Pa', number: 91, weight: 231.04, type: 'actinium' },
- { name: 'Uranium', symbol: 'U', number: 92, weight: 238.03, type: 'actinium' },
- { name: 'Neptunium', symbol: 'Np', number: 93, weight: 237, type: 'actinium' },
- { name: 'Plutonium', symbol: 'Pu', number: 94, weight: 244, type: 'actinium' },
- { name: 'Americium', symbol: 'Am', number: 95, weight: 243, type: 'actinium' },
- { name: 'Curium', symbol: 'Cm', number: 96, weight: 247, type: 'actinium' },
- { name: 'Berkelium', symbol: 'Bk', number: 97, weight: 247, type: 'actinium' },
- { name: 'Californium', symbol: 'Cf', number: 98, weight: 251, type: 'actinium' },
- { name: 'Einsteinium', symbol: 'Es', number: 99, weight: 252, type: 'actinium' },
- { name: 'Fermium', symbol: 'Fm', number: 100, weight: 257, type: 'actinium' },
- { name: 'Mendelevium', symbol: 'Md', number: 101, weight: 258, type: 'actinium' },
- { name: 'Nobelium', symbol: 'No', number: 102, weight: 259, type: 'actinium' },
- { name: 'Lawrencium', symbol: 'Lr', number: 103, weight: 262, type: 'actinium' },
- { name: '', symbol: '', number: -1, weight: 0, type: 'empty' },
- ],
-];
-
-export const niceTypes = {
- 'metal': "Metal",
- 'nonmetal': "Nonmetal",
- 'noblegas': "Noble gas",
- 'lanthanum': "Lanthanum",
- 'actinium': "Actinium"
-}
diff --git a/.config/ags/modules/cheatsheet/keybinds.js b/.config/ags/modules/cheatsheet/keybinds.js
deleted file mode 100644
index 2464f0a6c..000000000
--- a/.config/ags/modules/cheatsheet/keybinds.js
+++ /dev/null
@@ -1,126 +0,0 @@
-const { GLib, Gtk } = imports.gi;
-import App from "resource:///com/github/Aylur/ags/app.js";
-import * as Utils from "resource:///com/github/Aylur/ags/utils.js";
-import Widget from "resource:///com/github/Aylur/ags/widget.js";
-import { IconTabContainer } from "../.commonwidgets/tabcontainer.js";
-const { Box, Label, Scrollable } = Widget;
-
-const HYPRLAND_KEYBIND_CONFIG_FILE = userOptions.cheatsheet.keybinds.configPath ?
- userOptions.cheatsheet.keybinds.configPath : `${GLib.get_user_config_dir()}/hypr/hyprland/keybinds.conf`;
-const KEYBIND_SECTIONS_PER_PAGE = 3;
-const getKeybindList = () => {
- let data = Utils.exec(`${App.configDir}/scripts/hyprland/get_keybinds.py --path ${HYPRLAND_KEYBIND_CONFIG_FILE}`);
- if (data == "\"error\"") {
- Utils.timeout(2000, () => Utils.execAsync(['notify-send',
- 'Update path to keybinds',
- 'Keybinds hyprland config file not found. Check your user options.',
- '-a', 'ags',
- ]).catch(print))
- return { children: [] };
- }
- return JSON.parse(data);
-};
-const keybindList = getKeybindList();
-
-const keySubstitutions = {
- "Super": "",
- "mouse_up": "Scroll ↓", // ikr, weird
- "mouse_down": "Scroll ↑", // trust me bro
- "mouse:272": "LMB",
- "mouse:273": "RMB",
- "mouse:275": "MouseBack",
- "Slash": "/",
- "Hash": "#"
-}
-
-const substituteKey = (key) => {
- return keySubstitutions[key] || key;
-}
-
-const Keybind = (keybindData, type) => { // type: either "keys" or "actions"
- const Key = (key) => Label({ // Specific keys
- vpack: 'center',
- className: `${['OR', '+'].includes(key) ? 'cheatsheet-key-notkey' : 'cheatsheet-key'} txt-small`,
- label: substituteKey(key),
- });
- const Action = (text) => Label({ // Binds
- xalign: 0,
- label: getString(text),
- className: "txt txt-small cheatsheet-action",
- })
- return Widget.Box({
- className: "spacing-h-10 cheatsheet-bind-lineheight",
- children: type == "keys" ? [
- ...(keybindData.mods.length > 0 ? [
- ...keybindData.mods.map(Key),
- Key("+"),
- ] : []),
- Key(keybindData.key),
- ] : [Action(keybindData.comment)],
- })
-}
-
-const Section = (sectionData, scope) => {
- const keys = Box({
- vertical: true,
- className: 'spacing-v-5',
- children: sectionData.keybinds.map((data) => Keybind(data, "keys"))
- })
- const actions = Box({
- vertical: true,
- className: 'spacing-v-5',
- children: sectionData.keybinds.map((data) => Keybind(data, "actions"))
- })
- const name = Label({
- xalign: 0,
- className: "cheatsheet-category-title txt margin-bottom-10",
- label: getString(sectionData.name),
- })
- const binds = Box({
- className: 'spacing-h-10',
- children: [
- keys,
- actions,
- ]
- })
- const childrenSections = Box({
- vertical: true,
- className: 'spacing-v-15',
- children: sectionData.children.map((data) => Section(data, scope + 1))
- })
- return Box({
- vertical: true,
- children: [
- ...((sectionData.name && sectionData.name.length > 0) ? [name] : []),
- Box({
- className: 'spacing-v-10',
- children: [
- binds,
- childrenSections,
- ]
- })
- ]
- })
-};
-
-export default () => {
- const numOfTabs = Math.ceil(keybindList.children.length / KEYBIND_SECTIONS_PER_PAGE);
- const keybindPages = Array.from({ length: numOfTabs }, (_, i) => ({
- iconWidget: Label({
- className: "txt txt-small",
- label: `${i + 1}`,
- }),
- name: `${i + 1}`,
- child: Box({
- className: 'spacing-h-30',
- children: keybindList.children.slice(
- KEYBIND_SECTIONS_PER_PAGE * i, 0 + KEYBIND_SECTIONS_PER_PAGE * (i + 1),
- ).map(data => Section(data, 1)),
- }),
- }));
- return IconTabContainer({
- iconWidgets: keybindPages.map((kbp) => kbp.iconWidget),
- names: keybindPages.map((kbp) => kbp.name),
- children: keybindPages.map((kbp) => kbp.child),
- });
-};
diff --git a/.config/ags/modules/cheatsheet/main.js b/.config/ags/modules/cheatsheet/main.js
deleted file mode 100644
index 0d591ad46..000000000
--- a/.config/ags/modules/cheatsheet/main.js
+++ /dev/null
@@ -1,146 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import { setupCursorHover } from "../.widgetutils/cursorhover.js";
-import PopupWindow from '../.widgethacks/popupwindow.js';
-import Keybinds from "./keybinds.js";
-import PeriodicTable from "./periodictable.js";
-import { ExpandingIconTabContainer } from '../.commonwidgets/tabcontainer.js';
-import { checkKeybind } from '../.widgetutils/keybind.js';
-import clickCloseRegion from '../.commonwidgets/clickcloseregion.js';
-
-const cheatsheets = [
- {
- name: getString('Keybinds'),
- materialIcon: 'keyboard',
- contentWidget: Keybinds,
- },
- {
- name: getString('Periodic table'),
- materialIcon: 'experiment',
- contentWidget: PeriodicTable,
- },
-];
-
-const CheatsheetHeader = () => Widget.CenterBox({
- vertical: false,
- startWidget: Widget.Box({}),
- centerWidget: Widget.Box({
- vertical: true,
- className: "spacing-h-15",
- children: [
- Widget.Box({
- hpack: 'center',
- className: 'spacing-h-5 cheatsheet-title',
- children: [
- Widget.Label({
- hpack: 'center',
- css: 'margin-right: 0.682rem;',
- className: 'txt-title',
- label: getString('Cheat sheet'),
- }),
- Widget.Label({
- vpack: 'center',
- className: "cheatsheet-key txt-small",
- label: "",
- }),
- Widget.Label({
- vpack: 'center',
- className: "cheatsheet-key-notkey txt-small",
- label: "+",
- }),
- Widget.Label({
- vpack: 'center',
- className: "cheatsheet-key txt-small",
- label: "/",
- })
- ]
- }),
- ]
- }),
- endWidget: Widget.Button({
- vpack: 'start',
- hpack: 'end',
- className: "cheatsheet-closebtn icon-material txt txt-hugeass",
- onClicked: () => {
- closeWindowOnAllMonitors('cheatsheet');
- },
- child: Widget.Label({
- className: 'icon-material txt txt-hugeass',
- label: 'close'
- }),
- setup: setupCursorHover,
- }),
-});
-
-const sheetContents = [];
-const SheetContent = (id) => {
- sheetContents[id] = ExpandingIconTabContainer({
- tabsHpack: 'center',
- tabSwitcherClassName: 'sidebar-icontabswitcher',
- transitionDuration: userOptions.animations.durationLarge * 1.4,
- icons: cheatsheets.map((api) => api.materialIcon),
- names: cheatsheets.map((api) => api.name),
- children: cheatsheets.map((api) => api.contentWidget()),
- onChange: (self, id) => {
- self.shown = cheatsheets[id].name;
- }
- });
- return sheetContents[id];
-}
-
-export default (id) => {
- const sheets = SheetContent(id);
- const widgetContent = Widget.Box({
- vertical: true,
- className: "cheatsheet-bg spacing-v-5",
- children: [
- CheatsheetHeader(),
- sheets,
- ]
- });
- return PopupWindow({
- monitor: id,
- name: `cheatsheet${id}`,
- layer: 'top',
- keymode: 'on-demand',
- visible: false,
- anchor: ['top', 'bottom', 'left', 'right'],
- child: Widget.Box({
- vertical: true,
- children: [
- clickCloseRegion({ name: 'cheatsheet' }),
- Widget.Box({
- children: [
- clickCloseRegion({ name: 'cheatsheet' }),
- widgetContent,
- clickCloseRegion({ name: 'cheatsheet' }),
- ]
- }),
- clickCloseRegion({ name: 'cheatsheet' }),
- ],
- setup: (self) => self.on('key-press-event', (widget, event) => { // Typing
- // Whole sheet
- if (checkKeybind(event, userOptions.keybinds.cheatsheet.nextTab))
- sheetContents.forEach(tab => tab.nextTab())
- else if (checkKeybind(event, userOptions.keybinds.cheatsheet.prevTab))
- sheetContents.forEach(tab => tab.prevTab())
- else if (checkKeybind(event, userOptions.keybinds.cheatsheet.cycleTab))
- sheetContents.forEach(tab => tab.cycleTab())
- // Keybinds
- if (sheets.attribute.names[sheets.attribute.shown.value] == 'Keybinds') { // If Keybinds tab is focused
- if (checkKeybind(event, userOptions.keybinds.cheatsheet.keybinds.nextTab)) {
- sheetContents.forEach((sheet) => {
- const toSwitchTab = sheet.attribute.children[sheet.attribute.shown.value];
- toSwitchTab.nextTab();
- })
- }
- else if (checkKeybind(event, userOptions.keybinds.cheatsheet.keybinds.prevTab)) {
- sheetContents.forEach((sheet) => {
- const toSwitchTab = sheet.attribute.children[sheet.attribute.shown.value];
- toSwitchTab.prevTab();
- })
- }
- }
- })
- })
- });
-}
\ No newline at end of file
diff --git a/.config/ags/modules/cheatsheet/periodictable.js b/.config/ags/modules/cheatsheet/periodictable.js
deleted file mode 100644
index 92a85b9d5..000000000
--- a/.config/ags/modules/cheatsheet/periodictable.js
+++ /dev/null
@@ -1,94 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import { niceTypes, periodicTable, series } from "./data_periodictable.js";
-const { Box, Button, Icon, Label, Revealer } = Widget;
-
-export default () => {
- const ElementTile = (element) => {
- return Box({
- vertical: true,
- tooltipText: element.electronConfig ? `${element.electronConfig}` : null,
- className: `cheatsheet-periodictable-${element.type}`,
- children: element.name == '' ? null : [
- Box({
- className: 'padding-left-8 padding-right-8 padding-top-8',
- children: [
- Label({
- label: `${element.number}`,
- className: "cheatsheet-periodictable-elementnum txt-tiny txt-bold",
- }),
- Box({ hexpand: true }),
- Label({
- label: `${element.weight}`,
- className: "txt-smaller",
- })
- ]
- }),
- element.icon ? Icon({
- icon: element.icon,
- className: "txt-hugerass txt-bold",
- }) : Label({
- label: `${element.symbol}`,
- className: "cheatsheet-periodictable-elementsymbol",
- }),
- Label({
- label: `${element.name}`,
- className: "txt-tiny",
- })
- ]
- })
- }
- const BoardColor = (type) => Box({
- className: 'spacing-h-5',
- children: [
- Box({
- homogeneous: true,
- className: `cheatsheet-periodictable-legend-color-wrapper`,
- children: [Box({
- className: `cheatsheet-periodictable-legend-color-${type}`,
- })]
- }),
- Label({
- label: `${niceTypes[type]}`,
- className: "txt txt-small",
- })
- ]
- })
- const mainBoard = Box({
- hpack: 'center',
- vertical: true,
- className: "spacing-v-3",
- children: periodicTable.map((row, _) => Box({ // Rows
- className: "spacing-h-5",
- children: row.map((element, _) => ElementTile(element))
- })),
- });
- const seriesBoard = Box({
- hpack: 'center',
- vertical: true,
- className: "spacing-v-3",
- children: series.map((row, _) => Box({ // Rows
- className: "spacing-h-5",
- children: row.map((element, _) => ElementTile(element))
- })),
- });
- const legend = Box({
- hpack: 'center',
- className: 'spacing-h-20',
- children: [
- BoardColor('metal'),
- BoardColor('nonmetal'),
- BoardColor('noblegas'),
- BoardColor('lanthanum'),
- BoardColor('actinium'),
- ]
- })
- return Box({
- vertical: true,
- className: 'spacing-v-20',
- children: [
- mainBoard,
- seriesBoard,
- legend
- ]
- })
-}
\ No newline at end of file
diff --git a/.config/ags/modules/crosshair/main.js b/.config/ags/modules/crosshair/main.js
deleted file mode 100644
index 9d1538aa0..000000000
--- a/.config/ags/modules/crosshair/main.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import { enableClickthrough } from "../.widgetutils/clickthrough.js";
-
-export default (monitor = 0, ) => {
- return Widget.Window({
- monitor,
- name: `crosshair${monitor}`,
- layer: 'overlay',
- exclusivity: 'ignore',
- visible: false,
- child: Widget.Icon({
- icon: 'crosshair-symbolic',
- css: `
- font-size: ${userOptions.gaming.crosshair.size}px;
- color: ${userOptions.gaming.crosshair.color};
- `,
- }),
- setup: enableClickthrough,
- });
-}
-
diff --git a/.config/ags/modules/desktopbackground/data_quicklaunches.js b/.config/ags/modules/desktopbackground/data_quicklaunches.js
deleted file mode 100644
index a5a9562f1..000000000
--- a/.config/ags/modules/desktopbackground/data_quicklaunches.js
+++ /dev/null
@@ -1,14 +0,0 @@
-export const quickLaunchItems = [
- {
- "name": "GitHub + Files×2",
- "command": "github-desktop & nautilus --new-window & nautilus --new-window &"
- },
- {
- "name": "Terminal×2",
- "command": "foot & foot &"
- },
- {
- "name": "Discord + Youtube + Github",
- "command": "xdg-open 'https://discord.com/app' && xdg-open 'https://youtube.com/' && xdg-open 'https://github.com/' &"
- },
-]
\ No newline at end of file
diff --git a/.config/ags/modules/desktopbackground/main.js b/.config/ags/modules/desktopbackground/main.js
deleted file mode 100644
index 9600e151e..000000000
--- a/.config/ags/modules/desktopbackground/main.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-
-import WallpaperImage from './wallpaper.js';
-import TimeAndLaunchesWidget from './timeandlaunches.js'
-import SystemWidget from './system.js'
-
-export default (monitor) => Widget.Window({
- name: `desktopbackground${monitor}`,
- // anchor: ['top', 'bottom', 'left', 'right'],
- layer: 'background',
- exclusivity: 'ignore',
- visible: true,
- child: Widget.Overlay({
- child: WallpaperImage(monitor),
- // child: Widget.Box({}),
- overlays: [
- TimeAndLaunchesWidget(),
- SystemWidget(),
- ],
- setup: (self) => {
- self.set_overlay_pass_through(self.get_children()[1], true);
- },
- }),
-});
diff --git a/.config/ags/modules/desktopbackground/system.js b/.config/ags/modules/desktopbackground/system.js
deleted file mode 100644
index a65402b7c..000000000
--- a/.config/ags/modules/desktopbackground/system.js
+++ /dev/null
@@ -1,161 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { execAsync, exec } = Utils;
-const { Box, EventBox, Label, Revealer, Overlay } = Widget;
-import { AnimatedCircProg } from "../.commonwidgets/cairo_circularprogress.js";
-import { MaterialIcon } from '../.commonwidgets/materialicon.js';
-
-const ResourceValue = (name, icon, interval, valueUpdateCmd, displayFunc, props = {}) => Box({
- ...props,
- className: 'bg-system-bg txt',
- children: [
- Revealer({
- transition: 'slide_left',
- transitionDuration: userOptions.animations.durationLarge,
- child: Box({
- vpack: 'center',
- vertical: true,
- className: 'margin-right-15',
- children: [
- Label({
- xalign: 1,
- className: 'txt-small txt',
- label: `${name}`,
- }),
- Label({
- xalign: 1,
- className: 'titlefont txt-norm txt-onSecondaryContainer',
- setup: (self) => self
- .poll(interval, (label) => displayFunc(label))
- ,
- })
- ]
- })
- }),
- Overlay({
- child: AnimatedCircProg({
- className: 'bg-system-circprog',
- extraSetup: (self) => self
- .poll(interval, (self) => {
- execAsync(['bash', '-c', `${valueUpdateCmd}`]).then((newValue) => {
- self.css = `font-size: ${Math.round(newValue)}px;`
- }).catch(print);
- })
- ,
- }),
- overlays: [
- MaterialIcon(`${icon}`, 'hugeass'),
- ],
- setup: self => self.set_overlay_pass_through(self.get_children()[1], true),
- }),
- ]
-})
-
-const resources = Box({
- vpack: 'fill',
- vertical: true,
- className: 'spacing-v-15',
- children: [
- ResourceValue('Memory', 'memory', 10000, `free | awk '/^Mem/ {printf("%.2f\\n", ($3/$2) * 100)}'`,
- (label) => {
- execAsync(['bash', '-c', `free -h | awk '/^Mem/ {print $3 " / " $2}' | sed 's/Gi/Gib/g'`])
- .then((output) => {
- label.label = `${output}`
- }).catch(print);
- }, { hpack: 'end' }),
- ResourceValue('Swap', 'swap_horiz', 10000, `free | awk '/^Swap/ {if ($2 > 0) printf("%.2f\\n", ($3/$2) * 100); else print "0";}'`,
- (label) => {
- execAsync(['bash', '-c', `free -h | awk '/^Swap/ {if ($2 != "0") print $3 " / " $2; else print "No swap"}' | sed 's/Gi/Gib/g'`])
- .then((output) => {
- label.label = `${output}`
- }).catch(print);
- }, { hpack: 'end' }),
- ResourceValue('Disk space', 'hard_drive_2', 3600000, `echo $(df --output=pcent / | tr -dc '0-9')`,
- (label) => {
- execAsync(['bash', '-c', `df -h --output=avail / | awk 'NR==2{print $1}'`])
- .then((output) => {
- label.label = `${output} available`
- }).catch(print);
- }, { hpack: 'end' }),
- ]
-});
-
-const distroAndVersion = Box({
- vertical: true,
- children: [
- Box({
- hpack: 'end',
- children: [
- Label({
- className: 'bg-distro-txt',
- xalign: 0,
- label: 'Hyping on ',
- }),
- Label({
- className: 'bg-distro-name',
- xalign: 0,
- label: '',
- setup: (label) => {
- execAsync([`grep`, `-oP`, `PRETTY_NAME="\\K[^"]+`, `/etc/os-release`]).then(distro => {
- label.label = distro;
- }).catch(print);
- },
- }),
- ]
- }),
- Box({
- hpack: 'end',
- children: [
- Label({
- className: 'bg-distro-txt',
- xalign: 0,
- label: 'with ',
- }),
- Label({
- className: 'bg-distro-name',
- xalign: 0,
- label: 'An environment idk',
- setup: (label) => {
- // hyprctl will return unsuccessfully if Hyprland isn't running
- execAsync([`bash`, `-c`, `hyprctl version | grep -oP "Tag: v\\K\\d+\\.\\d+\\.\\d+"`]).then(version => {
- label.label = `Hyprland ${version}`;
- }).catch(() => execAsync([`bash`, `-c`, `sway -v | cut -d'-' -f1 | sed 's/sway version /v/'`]).then(version => {
- label.label = `Sway ${version}`;
- }).catch(print));
- },
- }),
- ]
- })
- ]
-})
-
-export default () => Box({
- hpack: 'end',
- vpack: 'end',
- children: [
- EventBox({
- child: Box({
- hpack: 'end',
- vpack: 'end',
- className: 'bg-distro-box spacing-v-20',
- vertical: true,
- children: [
- resources,
- distroAndVersion,
- ]
- }),
- onPrimaryClickRelease: () => {
- const kids = resources.get_children();
- for (let i = 0; i < kids.length; i++) {
- const child = kids[i];
- const firstChild = child.get_children()[0];
- firstChild.revealChild = !firstChild.revealChild;
- }
-
- },
- })
- ],
-})
-
-
-
diff --git a/.config/ags/modules/desktopbackground/timeandlaunches.js b/.config/ags/modules/desktopbackground/timeandlaunches.js
deleted file mode 100644
index f0e0214b4..000000000
--- a/.config/ags/modules/desktopbackground/timeandlaunches.js
+++ /dev/null
@@ -1,74 +0,0 @@
-const { GLib } = imports.gi;
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import Service from 'resource:///com/github/Aylur/ags/service.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-
-import Variable from 'resource:///com/github/Aylur/ags/variable.js';
-const { execAsync, exec } = Utils;
-const { Box, Label, Button, Revealer, EventBox } = Widget;
-import { setupCursorHover } from '../.widgetutils/cursorhover.js';
-import { quickLaunchItems } from './data_quicklaunches.js'
-
-const TimeAndDate = () => Box({
- vertical: true,
- className: 'spacing-v--5',
- children: [
- Label({
- className: 'bg-time-clock',
- xalign: 0,
- label: GLib.DateTime.new_now_local().format(userOptions.time.format),
- setup: (self) => self.poll(userOptions.time.interval, label => {
- label.label = GLib.DateTime.new_now_local().format(userOptions.time.format);
- }),
- }),
- Label({
- className: 'bg-time-date',
- xalign: 0,
- label: GLib.DateTime.new_now_local().format(userOptions.time.dateFormatLong),
- setup: (self) => self.poll(userOptions.time.dateInterval, (label) => {
- label.label = GLib.DateTime.new_now_local().format(userOptions.time.dateFormatLong);
- }),
- }),
- ]
-})
-
-const QuickLaunches = () => Box({
- vertical: true,
- className: 'spacing-v-10',
- children: [
- Label({
- xalign: 0,
- className: 'bg-quicklaunch-title',
- label: 'Quick Launches',
- }),
- Box({
- hpack: 'start',
- className: 'spacing-h-5',
- children: quickLaunchItems.map((item, i) => Button({
- onClicked: () => {
- execAsync(['bash', '-c', `${item["command"]}`]).catch(print);
- },
- className: 'bg-quicklaunch-btn',
- child: Label({
- label: `${item["name"]}`,
- }),
- setup: (self) => {
- setupCursorHover(self);
- }
- })),
- })
- ]
-})
-
-export default () => Box({
- hpack: 'start',
- vpack: 'end',
- vertical: true,
- className: 'bg-time-box spacing-h--10',
- children: [
- TimeAndDate(),
- // QuickLaunches(),
- ],
-})
-
diff --git a/.config/ags/modules/desktopbackground/wallpaper.js b/.config/ags/modules/desktopbackground/wallpaper.js
deleted file mode 100644
index 779bb2304..000000000
--- a/.config/ags/modules/desktopbackground/wallpaper.js
+++ /dev/null
@@ -1,119 +0,0 @@
-const { Gdk, GdkPixbuf, Gio, GLib, Gtk } = imports.gi;
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { exec, execAsync } = Utils;
-const { Box, Button, Label, Stack } = Widget;
-import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
-
-import Wallpaper from '../../services/wallpaper.js';
-import { setupCursorHover } from '../.widgetutils/cursorhover.js';
-import { clamp } from '../.miscutils/mathfuncs.js';
-import { monitors } from '../.commondata/hyprlanddata.js';
-
-const DISABLE_AGS_WALLPAPER = true;
-
-const SWITCHWALL_SCRIPT_PATH = `${App.configDir}/scripts/color_generation/switchwall.sh`;
-const WALLPAPER_ZOOM_SCALE = 1.25; // For scrolling when we switch workspace
-const MAX_WORKSPACES = 10;
-
-export default (monitor = 0) => {
- const WALLPAPER_OFFSCREEN_X = (WALLPAPER_ZOOM_SCALE - 1) * monitors[monitor].width;
- const WALLPAPER_OFFSCREEN_Y = (WALLPAPER_ZOOM_SCALE - 1) * monitors[monitor].height;
- const wallpaperImage = Widget.DrawingArea({
- attribute: {
- pixbuf: undefined,
- workspace: 1,
- sideleft: 0,
- sideright: 0,
- updatePos: (self) => {
- self.setCss(`font-size: ${self.attribute.workspace - self.attribute.sideleft + self.attribute.sideright}px;`)
- },
- },
- className: 'bg-wallpaper-transition',
- setup: (self) => {
- self.set_size_request(monitors[monitor].width, monitors[monitor].height);
- self
- // TODO: reduced updates using timeouts to reduce lag
- // .hook(Hyprland.active.workspace, (self) => {
- // self.attribute.workspace = Hyprland.active.workspace.id
- // self.attribute.updatePos(self);
- // })
- // .hook(App, (box, name, visible) => { // Update on open
- // if (self.attribute[name] === undefined) return;
- // self.attribute[name] = (visible ? 1 : 0);
- // self.attribute.updatePos(self);
- // })
- .on('draw', (self, cr) => {
- if (!self.attribute.pixbuf) return;
- const styleContext = self.get_style_context();
- const workspace = styleContext.get_property('font-size', Gtk.StateFlags.NORMAL);
- // Draw
- Gdk.cairo_set_source_pixbuf(cr, self.attribute.pixbuf,
- -(WALLPAPER_OFFSCREEN_X / (MAX_WORKSPACES + 1) * (clamp(workspace, 0, MAX_WORKSPACES + 1))),
- -WALLPAPER_OFFSCREEN_Y / 2);
- cr.paint();
- })
- .hook(Wallpaper, (self) => {
- if (DISABLE_AGS_WALLPAPER) return;
- const wallPath = Wallpaper.get(monitor);
- if (!wallPath || wallPath === "") return;
- self.attribute.pixbuf = GdkPixbuf.Pixbuf.new_from_file(wallPath);
-
- const scale_x = monitors[monitor].width * WALLPAPER_ZOOM_SCALE / self.attribute.pixbuf.get_width();
- const scale_y = monitors[monitor].height * WALLPAPER_ZOOM_SCALE / self.attribute.pixbuf.get_height();
- const scale_factor = Math.max(scale_x, scale_y);
-
- self.attribute.pixbuf = self.attribute.pixbuf.scale_simple(
- Math.round(self.attribute.pixbuf.get_width() * scale_factor),
- Math.round(self.attribute.pixbuf.get_height() * scale_factor),
- GdkPixbuf.InterpType.BILINEAR
- );
- self.queue_draw();
- }, 'updated');
- ;
- }
- ,
- });
- const wallpaperPrompt = Box({
- hpack: 'center',
- vpack: 'center',
- vertical: true,
- className: 'spacing-v-10',
- children: [
- Label({
- hpack: 'center',
- justification: 'center',
- className: 'txt-large',
- label: `No wallpaper loaded.\nAn image ≥ ${monitors[monitor].width * WALLPAPER_ZOOM_SCALE} × ${monitors[monitor].height * WALLPAPER_ZOOM_SCALE} is recommended.`,
- }),
- Button({
- hpack: 'center',
- className: 'btn-primary',
- label: `Select one`,
- setup: setupCursorHover,
- onClicked: (self) => Utils.execAsync([SWITCHWALL_SCRIPT_PATH]).catch(print),
- }),
- ]
- });
- const stack = Stack({
- transition: 'crossfade',
- transitionDuration: userOptions.animations.durationLarge,
- children: {
- 'disabled': Box({}),
- 'image': wallpaperImage,
- 'prompt': wallpaperPrompt,
- },
- setup: (self) => self
- .hook(Wallpaper, (self) => {
- if (DISABLE_AGS_WALLPAPER) {
- self.shown = 'disabled';
- return;
- }
- const wallPath = Wallpaper.get(monitor);
- self.shown = ((wallPath && wallPath != "") ? 'image' : 'prompt');
- }, 'updated')
- ,
- })
- return stack;
- // return wallpaperImage;
-}
diff --git a/.config/ags/modules/dock/dock.js b/.config/ags/modules/dock/dock.js
deleted file mode 100755
index bd8297f93..000000000
--- a/.config/ags/modules/dock/dock.js
+++ /dev/null
@@ -1,315 +0,0 @@
-const { Gtk, GLib } = imports.gi;
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { EventBox, Button } = Widget;
-
-import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
-import Applications from 'resource:///com/github/Aylur/ags/service/applications.js';
-const { execAsync, exec } = Utils;
-const { Box, Revealer } = Widget;
-import { setupCursorHover } from '../.widgetutils/cursorhover.js';
-import { getAllFiles, searchIcons } from './icons.js'
-import { MaterialIcon } from '../.commonwidgets/materialicon.js';
-import { substitute } from '../.miscutils/icons.js';
-
-const icon_files = userOptions.icons.searchPaths.map(e => getAllFiles(e)).flat(1)
-
-let isPinned = false
-let cachePath = new Map()
-
-let timers = []
-
-function clearTimes() {
- timers.forEach(e => GLib.source_remove(e))
- timers = []
-}
-
-function ExclusiveWindow(client) {
- const fn = [
- (client) => !(client !== null && client !== undefined),
- // Jetbrains
- (client) => client.title.includes("win"),
- // Vscode
- (client) => client.title === '' && client.class === ''
- ]
-
- for (const item of fn) { if (item(client)) { return true } }
- return false
-}
-
-const focus = ({ address }) => Utils.execAsync(`hyprctl dispatch focuswindow address:${address}`).catch(print);
-
-const DockSeparator = (props = {}) => Box({
- ...props,
- className: 'dock-separator',
-})
-
-const PinButton = () => Widget.Button({
- className: 'dock-app-btn dock-app-btn-animate',
- tooltipText: 'Pin Dock',
- child: Widget.Box({
- homogeneous: true,
- className: 'dock-app-icon txt',
- child: MaterialIcon('push_pin', 'hugeass')
- }),
- onClicked: (self) => {
- isPinned = !isPinned
- self.className = `${isPinned ? "pinned-dock-app-btn" : "dock-app-btn animate"} dock-app-btn-animate`
- },
- setup: setupCursorHover,
-})
-
-const LauncherButton = () => Widget.Button({
- className: 'dock-app-btn dock-app-btn-animate',
- tooltipText: 'Open launcher',
- child: Widget.Box({
- homogeneous: true,
- className: 'dock-app-icon txt',
- child: MaterialIcon('apps', 'hugerass')
- }),
- onClicked: (self) => {
- App.toggleWindow('overview');
- },
- setup: setupCursorHover,
-})
-
-const AppButton = ({ icon, ...rest }) => Widget.Revealer({
- attribute: {
- 'workspace': 0
- },
- revealChild: false,
- transition: 'slide_right',
- transitionDuration: userOptions.animations.durationLarge,
- child: Widget.Button({
- ...rest,
- className: 'dock-app-btn dock-app-btn-animate',
- child: Widget.Box({
- child: Widget.Overlay({
- child: Widget.Box({
- homogeneous: true,
- className: 'dock-app-icon',
- child: Widget.Icon({
- icon: icon,
- }),
- }),
- overlays: [Widget.Box({
- class_name: 'indicator',
- vpack: 'end',
- hpack: 'center',
- })],
- }),
- }),
- setup: (button) => {
- setupCursorHover(button);
- }
- })
-});
-
-const Taskbar = (monitor) => Widget.Box({
- className: 'dock-apps',
- attribute: {
- monitor: monitor,
- 'map': new Map(),
- 'clientSortFunc': (a, b) => {
- return a.attribute.workspace > b.attribute.workspace;
- },
- 'update': (box, monitor) => {
- for (let i = 0; i < Hyprland.clients.length; i++) {
- const client = Hyprland.clients[i];
- if (client["pid"] == -1) return;
- const appClass = substitute(client.class);
- const ignoredAppsRegex = userOptions.dock.ignoredAppsRegex || [];
- let isIgnored = false;
-
- for (const regex of ignoredAppsRegex) {
- try {
- const pattern = new RegExp(regex);
- if (pattern.test(appClass)) {
- isIgnored = true;
- break;
- }
- } catch (e) {}
- }
-
- if (isIgnored) continue;
-
- // for (const appName of userOptions.dock.pinnedApps) {
- // if (appClass.includes(appName.toLowerCase()))
- // return null;
- // }
- let appClassLower = appClass.toLowerCase()
- let path = ''
- if (cachePath[appClassLower]) { path = cachePath[appClassLower] }
- else {
- path = searchIcons(appClass.toLowerCase(), icon_files)
- cachePath[appClassLower] = path
- }
- if (path === '') { path = substitute(appClass) }
- const newButton = AppButton({
- icon: path,
- tooltipText: `${client.title} (${appClass})`,
- onClicked: () => focus(client),
- });
- newButton.attribute.workspace = client.workspace.id;
- newButton.revealChild = true;
- box.attribute.map.set(client.address, newButton);
- }
- box.children = Array.from(box.attribute.map.values());
- },
- 'add': (box, address, monitor) => {
- if (!address) { // First active emit is undefined
- box.attribute.update(box);
- return;
- }
- const newClient = Hyprland.clients.find(client => {
- return client.address == address;
- });
- if (ExclusiveWindow(newClient)) { return }
- let appClass = newClient.class
- let appClassLower = appClass.toLowerCase()
- let path = ''
- if (cachePath[appClassLower]) { path = cachePath[appClassLower] }
- else {
- path = searchIcons(appClassLower, icon_files)
- cachePath[appClassLower] = path
- }
- if (path === '') { path = substitute(appClass) }
- const newButton = AppButton({
- icon: path,
- tooltipText: `${newClient.title} (${appClass})`,
- onClicked: () => focus(newClient),
- })
- newButton.attribute.workspace = newClient.workspace.id;
- box.attribute.map.set(address, newButton);
- box.children = Array.from(box.attribute.map.values());
- newButton.revealChild = true;
- },
- 'remove': (box, address) => {
- if (!address) return;
-
- const removedButton = box.attribute.map.get(address);
- if (!removedButton) return;
- removedButton.revealChild = false;
-
- Utils.timeout(userOptions.animations.durationLarge, () => {
- removedButton.destroy();
- box.attribute.map.delete(address);
- box.children = Array.from(box.attribute.map.values());
- })
- },
- },
- setup: (self) => {
- self.hook(Hyprland, (box, address) => box.attribute.add(box, address, self.monitor), 'client-added')
- .hook(Hyprland, (box, address) => box.attribute.remove(box, address, self.monitor), 'client-removed')
- Utils.timeout(100, () => self.attribute.update(self));
- },
-});
-
-const PinnedApps = () => Widget.Box({
- class_name: 'dock-apps',
- homogeneous: true,
- children: userOptions.dock.pinnedApps
- .map(term => ({ app: Applications.query(term)?.[0], term }))
- .filter(({ app }) => app)
- .map(({ app, term = true }) => {
- const newButton = AppButton({
- // different icon, emm...
- icon: userOptions.dock.searchPinnedAppIcons ?
- searchIcons(app.name, icon_files) :
- app.icon_name,
- onClicked: () => {
- for (const client of Hyprland.clients) {
- if (client.class.toLowerCase().includes(term))
- return focus(client);
- }
-
- app.launch();
- },
- onMiddleClick: () => app.launch(),
- tooltipText: app.name,
- setup: (self) => {
- self.revealChild = true;
- self.hook(Hyprland, button => {
- const running = Hyprland.clients
- .find(client => client.class.toLowerCase().includes(term)) || false;
-
- button.toggleClassName('notrunning', !running);
- button.toggleClassName('focused', Hyprland.active.client.address == running.address);
- button.set_tooltip_text(running ? running.title : app.name);
- }, 'notify::clients')
- },
- })
- newButton.revealChild = true;
- return newButton;
- }),
-});
-
-export default (monitor = 0) => {
- const dockContent = Box({
- className: 'dock-bg spacing-h-5',
- children: [
- PinButton(),
- PinnedApps(),
- DockSeparator(),
- Taskbar(),
- LauncherButton(),
- ]
- })
- const dockRevealer = Revealer({
- attribute: {
- 'updateShow': self => { // I only use mouse to resize. I don't care about keyboard resize if that's a thing
- if (userOptions.dock.monitorExclusivity)
- self.revealChild = Hyprland.active.monitor.id === monitor;
- else
- self.revealChild = true;
-
- return self.revealChild
- }
- },
- revealChild: false,
- transition: 'slide_up',
- transitionDuration: userOptions.animations.durationLarge,
- child: dockContent,
- setup: (self) => {
- const callback = (self, trigger) => {
- if (!userOptions.dock.trigger.includes(trigger)) return
- const flag = self.attribute.updateShow(self)
-
- if (flag) clearTimes();
-
- const hidden = userOptions.dock.autoHide.find(e => e["trigger"] === trigger)
-
- if (hidden) {
- let id = Utils.timeout(hidden.interval, () => {
- if (!isPinned) { self.revealChild = false }
- timers = timers.filter(e => e !== id)
- })
- timers.push(id)
- }
- }
-
- self
- // .hook(Hyprland, (self) => self.attribute.updateShow(self))
- .hook(Hyprland.active.workspace, self => callback(self, "workspace-active"))
- .hook(Hyprland.active.client, self => callback(self, "client-active"))
- .hook(Hyprland, self => callback(self, "client-added"), "client-added")
- .hook(Hyprland, self => callback(self, "client-removed"), "client-removed")
- },
- })
- return EventBox({
- onHover: () => {
- dockRevealer.revealChild = true;
- clearTimes()
- },
- child: Box({
- homogeneous: true,
- css: `min-height: ${userOptions.dock.hiddenThickness}px;`,
- children: [dockRevealer],
- }),
- setup: self => self.on("leave-notify-event", () => {
- if (!isPinned) dockRevealer.revealChild = false;
- clearTimes()
- })
- })
-}
diff --git a/.config/ags/modules/dock/icons.js b/.config/ags/modules/dock/icons.js
deleted file mode 100644
index 60f01a3a1..000000000
--- a/.config/ags/modules/dock/icons.js
+++ /dev/null
@@ -1,63 +0,0 @@
-const { Gio, GLib } = imports.gi
-
-const exists = (path) => Gio.File.new_for_path(path).query_exists(null);
-
-export const levenshteinDistance = (a, b) => {
- if (!a.length) { return b.length }
- if (!b.length) { return a.length }
-
- let f = Array.from(new Array(a.length + 1),
- () => new Array(b.length + 1).fill(0))
-
- for (let i = 0; i <= b.length; i++) { f[0][i] = i; }
- for (let i = 0; i <= a.length; i++) { f[i][0] = i; }
-
- for (let i = 1; i <= a.length; i++) {
- for (let j = 1; j <= b.length; j++) {
- if (a.charAt(i - 1) === b.charAt(j - 1)) {
- f[i][j] = f[i-1][j-1]
- } else {
- f[i][j] = Math.min(f[i-1][j-1], Math.min(f[i][j-1], f[i-1][j])) + 1
- }
- }
- }
-
- return f[a.length][b.length]
-}
-
-export const getAllFiles = (dir, files = []) => {
- if (!exists(dir)) { return [] }
- const file = Gio.File.new_for_path(dir);
- const enumerator = file.enumerate_children('standard::name,standard::type',
- Gio.FileQueryInfoFlags.NONE, null);
-
- for (const info of enumerator) {
- if (info.get_file_type() === Gio.FileType.DIRECTORY) {
- files.push(getAllFiles(`${dir}/${info.get_name()}`))
- } else {
- files.push(`${dir}/${info.get_name()}`)
- }
- }
-
- return files.flat(1);
-}
-
-export const searchIcons = (appClass, files) => {
- appClass = appClass.toLowerCase()
-
- if (!files.length) { return "" }
-
- let appro = 0x3f3f3f3f
- let path = ""
-
- for (const item of files) {
- let score = levenshteinDistance(item.split("/").pop().toLowerCase().split(".")[0], appClass)
-
- if (score < appro) {
- appro = score
- path = item
- }
- }
-
- return path
-}
\ No newline at end of file
diff --git a/.config/ags/modules/dock/main.js b/.config/ags/modules/dock/main.js
deleted file mode 100644
index 77d394d9f..000000000
--- a/.config/ags/modules/dock/main.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import Dock from './dock.js';
-
-export default (monitor = 0) => Widget.Window({
- monitor,
- name: `dock${monitor}`,
- layer: userOptions.dock.layer,
- anchor: ['bottom'],
- exclusivity: 'normal',
- visible: true,
- child: Dock(monitor),
-});
diff --git a/.config/ags/modules/indicators/colorscheme.js b/.config/ags/modules/indicators/colorscheme.js
deleted file mode 100644
index f43a41fa4..000000000
--- a/.config/ags/modules/indicators/colorscheme.js
+++ /dev/null
@@ -1,236 +0,0 @@
-const { Gio, GLib } = imports.gi;
-import Variable from 'resource:///com/github/Aylur/ags/variable.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import { ConfigToggle, ConfigMulipleSelection } from '../.commonwidgets/configwidgets.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { execAsync } = Utils;
-import { setupCursorHover } from '../.widgetutils/cursorhover.js';
-import { showColorScheme } from '../../variables.js';
-import { MaterialIcon } from '../.commonwidgets/materialicon.js';
-import { darkMode } from '../.miscutils/system.js';
-
-const ColorBox = ({
- name = 'Color',
- ...rest
-}) => Widget.Box({
- ...rest,
- homogeneous: true,
- children: [
- Widget.Label({
- label: `${name}`,
- })
- ]
-})
-
-const ColorSchemeSettingsRevealer = () => {
- const headerButtonIcon = MaterialIcon('expand_more', 'norm');
- const header = Widget.Button({
- className: 'osd-settings-btn-arrow',
- onClicked: () => {
- content.revealChild = !content.revealChild;
- headerButtonIcon.label = content.revealChild ? 'expand_less' : 'expand_more';
- },
- setup: setupCursorHover,
- hpack: 'end',
- child: headerButtonIcon,
- });
- const content = Widget.Revealer({
- revealChild: false,
- transition: 'slide_down',
- transitionDuration: 200,
- child: ColorSchemeSettings(),
- setup: (self) => self.hook(isHoveredColorschemeSettings, (revealer) => {
- if (isHoveredColorschemeSettings.value == false) {
- setTimeout(() => {
- if (isHoveredColorschemeSettings.value == false)
- revealer.revealChild = false;
- headerButtonIcon.label = 'expand_more';
- }, 1500);
- }
- }),
- });
- return Widget.EventBox({
- onHover: (self) => {
- isHoveredColorschemeSettings.setValue(true);
- },
- onHoverLost: (self) => {
- isHoveredColorschemeSettings.setValue(false);
- },
- child: Widget.Box({
- vertical: true,
- children: [
- header,
- content,
- ]
- }),
- });
-}
-
-function calculateSchemeInitIndex(optionsArr, searchValue = 'vibrant') {
- if (searchValue == '')
- searchValue = 'vibrant';
- const flatArray = optionsArr.flatMap(subArray => subArray);
- const result = flatArray.findIndex(element => element.value === searchValue);
- const rowIndex = Math.floor(result / optionsArr[0].length);
- const columnIndex = result % optionsArr[0].length;
- return [rowIndex, columnIndex];
-}
-
-const schemeOptionsArr = [
- [
- { name: getString('Tonal Spot'), value: 'tonalspot' },
- { name: getString('Fruit Salad'), value: 'fruitsalad' },
- { name: getString('Fidelity'), value: 'fidelity' },
- { name: getString('Rainbow'), value: 'rainbow' },
- ],
- [
- { name: getString('Neutral'), value: 'neutral' },
- { name: getString('Monochrome'), value: 'monochrome' },
- { name: getString('Expressive'), value: 'expressive' },
- { name: getString('Vibrant'), value: 'vibrant' },
- ],
- [
- { name: getString('Vibrant+'), value: 'morevibrant' },
- ],
- //[
- // { name: getString('Content'), value: 'content' },
- //]
-];
-
-const LIGHTDARK_FILE_LOCATION = `${GLib.get_user_state_dir()}/ags/user/colormode.txt`;
-const initTransparency = Utils.exec(`bash -c "sed -n \'2p\' ${LIGHTDARK_FILE_LOCATION}"`);
-const initTransparencyVal = (initTransparency == "transparent") ? 1 : 0;
-const initScheme = Utils.exec(`bash -c "sed -n \'3p\' ${LIGHTDARK_FILE_LOCATION}"`);
-const initSchemeIndex = calculateSchemeInitIndex(schemeOptionsArr, initScheme);
-
-const ColorSchemeSettings = () => Widget.Box({
- className: 'osd-colorscheme-settings spacing-v-5 margin-20',
- vertical: true,
- vpack: 'center',
- children: [
- Widget.Box({
- vertical: true,
- children: [
- Widget.Label({
- xalign: 0,
- className: 'txt-norm titlefont txt',
- label: getString('Options'),
- hpack: 'center',
- }),
- //////////////////
- ConfigToggle({
- icon: 'dark_mode',
- name: getString('Dark Mode'),
- desc: getString('Ya should go to sleep!'),
- initValue: darkMode.value,
- onChange: (_, newValue) => {
- darkMode.value = !!newValue;
- },
- extraSetup: (self) => self.hook(darkMode, (self) => {
- self.attribute.enabled.value = darkMode.value;
- }),
- }),
- ConfigToggle({
- icon: 'border_clear',
- name: getString('Transparency'),
- desc: getString('Make shell elements transparent'),
- initValue: initTransparencyVal,
- onChange: (self, newValue) => {
- let transparency = newValue == 0 ? "opaque" : "transparent";
- execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_state_dir()}/ags/user && sed -i "2s/.*/${transparency}/" ${GLib.get_user_state_dir()}/ags/user/colormode.txt`])
- .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchcolor.sh`]))
- .catch(print);
- },
- }),
- ]
- }),
- Widget.Box({
- vertical: true,
- className: 'spacing-v-5',
- children: [
- Widget.Label({
- xalign: 0,
- className: 'txt-norm titlefont txt margin-top-5',
- label: getString('Scheme styles'),
- hpack: 'center',
- }),
- //////////////////
- ConfigMulipleSelection({
- hpack: 'center',
- vpack: 'center',
- optionsArr: schemeOptionsArr,
- initIndex: initSchemeIndex,
- onChange: (value, name) => {
- execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_state_dir()}/ags/user && sed -i "3s/.*/${value}/" ${GLib.get_user_state_dir()}/ags/user/colormode.txt`])
- .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchcolor.sh`]))
- .catch(print);
- },
- }),
- ]
- })
- ]
-});
-
-const ColorschemeContent = () => Widget.Box({
- className: 'osd-colorscheme spacing-v-5',
- vertical: true,
- hpack: 'center',
- children: [
- Widget.Label({
- xalign: 0,
- className: 'txt-norm titlefont txt',
- label: getString('Color scheme'),
- hpack: 'center',
- }),
- Widget.Box({
- className: 'spacing-h-5',
- hpack: 'center',
- children: [
- ColorBox({ name: 'P', className: 'osd-color osd-color-primary' }),
- ColorBox({ name: 'S', className: 'osd-color osd-color-secondary' }),
- ColorBox({ name: 'T', className: 'osd-color osd-color-tertiary' }),
- ColorBox({ name: 'Sf', className: 'osd-color osd-color-surface' }),
- ColorBox({ name: 'Sf-i', className: 'osd-color osd-color-inverseSurface' }),
- ColorBox({ name: 'E', className: 'osd-color osd-color-error' }),
- ]
- }),
- Widget.Box({
- className: 'spacing-h-5',
- hpack: 'center',
- children: [
- ColorBox({ name: 'P-c', className: 'osd-color osd-color-primaryContainer' }),
- ColorBox({ name: 'S-c', className: 'osd-color osd-color-secondaryContainer' }),
- ColorBox({ name: 'T-c', className: 'osd-color osd-color-tertiaryContainer' }),
- ColorBox({ name: 'Sf-c', className: 'osd-color osd-color-surfaceContainer' }),
- ColorBox({ name: 'Sf-v', className: 'osd-color osd-color-surfaceVariant' }),
- ColorBox({ name: 'E-c', className: 'osd-color osd-color-errorContainer' }),
- ]
- }),
- ColorSchemeSettingsRevealer(),
- ]
-});
-
-const isHoveredColorschemeSettings = Variable(false);
-
-export default () => Widget.Revealer({
- transition: 'slide_down',
- transitionDuration: userOptions.animations.durationLarge,
- child: ColorschemeContent(),
- setup: (self) => {
- self
- .hook(showColorScheme, (revealer) => {
- if (showColorScheme.value == true)
- revealer.revealChild = true;
- else
- revealer.revealChild = isHoveredColorschemeSettings.value;
- })
- .hook(isHoveredColorschemeSettings, (revealer) => {
- if (isHoveredColorschemeSettings.value == false) {
- setTimeout(() => {
- if (isHoveredColorschemeSettings.value == false)
- revealer.revealChild = showColorScheme.value;
- }, 2000);
- }
- })
- },
-})
diff --git a/.config/ags/modules/indicators/indicatorvalues.js b/.config/ags/modules/indicators/indicatorvalues.js
deleted file mode 100644
index f8d08bfc3..000000000
--- a/.config/ags/modules/indicators/indicatorvalues.js
+++ /dev/null
@@ -1,133 +0,0 @@
-// This file is for brightness/volume indicators
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import Audio from 'resource:///com/github/Aylur/ags/service/audio.js';
-const { Box, Label, ProgressBar } = Widget;
-import { MarginRevealer } from '../.widgethacks/advancedrevealers.js';
-import Brightness from '../../services/brightness.js';
-import Indicator from '../../services/indicator.js';
-import { MaterialIcon } from '../.commonwidgets/materialicon.js';
-
-const OsdValue = ({
- name, icon, nameSetup = undefined, labelSetup, progressSetup,
- extraClassName = '', extraProgressClassName = '',
- ...rest
-}) => {
- const valueName = Label({
- xalign: 0, yalign: 0, hexpand: true,
- className: 'osd-label',
- label: `${name}`,
- setup: nameSetup,
- });
- const valueNumber = Label({
- hexpand: false, className: 'osd-value-txt',
- setup: labelSetup,
- });
- return Box({ // Volume
- hexpand: true,
- className: `osd-bg osd-value ${extraClassName} spacing-h-5`,
- attribute: {
- 'disable': () => {
- valueNumber.label = '';
- }
- },
- children: [
- MaterialIcon(icon, 'hugeass', {vpack: 'center'}),
- Box({
- vertical: true,
- className: 'spacing-v-5',
- vpack: 'center',
- children: [
- Box({
- children: [
- valueName,
- valueNumber,
- ]
- }),
- ProgressBar({
- className: `osd-progress ${extraProgressClassName}`,
- hexpand: true,
- vertical: false,
- setup: progressSetup,
- })
- ]
- })
- ],
- ...rest,
- });
-}
-
-export default (monitor = 0) => {
- const brightnessIndicator = OsdValue({
- name: 'Brightness',
- icon: 'light_mode',
- extraClassName: 'osd-brightness',
- extraProgressClassName: 'osd-brightness-progress',
- labelSetup: (self) => self.hook(Brightness[monitor], self => {
- self.label = `${Math.round(Brightness[monitor].screen_value * 100)}`;
- }, 'notify::screen-value'),
- progressSetup: (self) => self.hook(Brightness[monitor], (progress) => {
- const updateValue = Brightness[monitor].screen_value;
- if (updateValue !== progress.value) Indicator.popup(1);
- progress.value = updateValue;
- }, 'notify::screen-value'),
- });
-
- const volumeIndicator = OsdValue({
- name: 'Volume',
- icon: 'volume_up',
- extraClassName: 'osd-volume',
- extraProgressClassName: 'osd-volume-progress',
- attribute: { headphones: undefined , device: undefined},
- nameSetup: (self) => Utils.timeout(1, () => {
- const updateAudioDevice = (self) => {
- const usingHeadphones = (Audio.speaker?.stream?.port)?.toLowerCase().includes('headphone');
- if (volumeIndicator.attribute.headphones === undefined ||
- volumeIndicator.attribute.headphones !== usingHeadphones) {
- volumeIndicator.attribute.headphones = usingHeadphones;
- self.label = usingHeadphones ? 'Headphones' : 'Speakers';
- // Indicator.popup(1);
- }
- }
- self.hook(Audio, updateAudioDevice);
- Utils.timeout(1000, updateAudioDevice);
- }),
- labelSetup: (self) => self.hook(Audio, (label) => {
- const newDevice = (Audio.speaker?.name);
- const updateValue = Math.round(Audio.speaker?.volume * 100);
- if (!isNaN(updateValue)) {
- if (newDevice === volumeIndicator.attribute.device && updateValue != label.label) {
- Indicator.popup(1);
- }
- }
- volumeIndicator.attribute.device = newDevice;
- label.label = `${updateValue}`;
- }),
- progressSetup: (self) => self.hook(Audio, (progress) => {
- const updateValue = Audio.speaker?.volume;
- if (!isNaN(updateValue)) {
- if (updateValue > 1) progress.value = 1;
- else progress.value = updateValue;
- }
- }),
- });
- return MarginRevealer({
- transition: 'slide_down',
- showClass: 'osd-show',
- hideClass: 'osd-hide',
- extraSetup: (self) => self
- .hook(Indicator, (revealer, value) => {
- if (value > -1) revealer.attribute.show();
- else revealer.attribute.hide();
- }, 'popup')
- ,
- child: Box({
- hpack: 'center',
- vertical: false,
- className: 'spacing-h--10',
- children: [
- brightnessIndicator,
- volumeIndicator,
- ]
- })
- });
-}
diff --git a/.config/ags/modules/indicators/main.js b/.config/ags/modules/indicators/main.js
deleted file mode 100644
index 16741937f..000000000
--- a/.config/ags/modules/indicators/main.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import Indicator from '../../services/indicator.js';
-import IndicatorValues from './indicatorvalues.js';
-import MusicControls from './musiccontrols.js';
-import ColorScheme from './colorscheme.js';
-import NotificationPopups from './notificationpopups.js';
-
-export default (monitor = 0) => Widget.Window({
- name: `indicator${monitor}`,
- monitor,
- className: 'indicator',
- layer: 'overlay',
- // exclusivity: 'ignore',
- visible: true,
- anchor: ['top'],
- child: Widget.EventBox({
- onHover: () => { //make the widget hide when hovering
- Indicator.popup(-1);
- },
- child: Widget.Box({
- vertical: true,
- className: 'osd-window',
- css: 'min-height: 2px;',
- children: [
- IndicatorValues(monitor),
- MusicControls(),
- NotificationPopups(),
- ColorScheme(),
- ]
- })
- }),
-});
diff --git a/.config/ags/modules/indicators/musiccontrols.js b/.config/ags/modules/indicators/musiccontrols.js
deleted file mode 100644
index 5f5183462..000000000
--- a/.config/ags/modules/indicators/musiccontrols.js
+++ /dev/null
@@ -1,418 +0,0 @@
-const { GLib } = imports.gi;
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js';
-const { exec, execAsync } = Utils;
-const { Box, EventBox, Icon, Scrollable, Label, Button, Revealer } = Widget;
-
-import { fileExists } from '../.miscutils/files.js';
-import { AnimatedCircProg } from "../.commonwidgets/cairo_circularprogress.js";
-import { showMusicControls } from '../../variables.js';
-import { darkMode, hasPlasmaIntegration } from '../.miscutils/system.js';
-import { setupCursorHover } from '../.widgetutils/cursorhover.js';
-
-const COMPILED_STYLE_DIR = `${GLib.get_user_cache_dir()}/ags/user/generated`
-const LIGHTDARK_FILE_LOCATION = `${GLib.get_user_state_dir()}/ags/user/colormode.txt`;
-const colorMode = Utils.exec(`bash -c "sed -n \'1p\' '${LIGHTDARK_FILE_LOCATION}'"`);
-const lightDark = (colorMode == "light") ? 'light' : '';
-const COVER_COLORSCHEME_SUFFIX = '_colorscheme.css';
-var lastCoverPath = '';
-
-function isRealPlayer(player) {
- return (
- // Remove unecessary native buses from browsers if there's plasma integration
- // !(hasPlasmaIntegration && player.busName.startsWith('org.mpris.MediaPlayer2.firefox')) &&
- // !(hasPlasmaIntegration && player.busName.startsWith('org.mpris.MediaPlayer2.chromium')) &&
- // playerctld just copies other buses and we don't need duplicates
- !player.busName.startsWith('org.mpris.MediaPlayer2.playerctld') &&
- // Non-instance mpd bus
- !(player.busName.endsWith('.mpd') && !player.busName.endsWith('MediaPlayer2.mpd'))
- );
-}
-
-export const getPlayer = (name = userOptions.music.preferredPlayer) => Mpris.getPlayer(name) || Mpris.players[0] || null;
-function lengthStr(length) {
- const min = Math.floor(length / 60);
- const sec = Math.floor(length % 60);
- const sec0 = sec < 10 ? '0' : '';
- return `${min}:${sec0}${sec}`;
-}
-
-function detectMediaSource(link) {
- if (link.startsWith("file://")) {
- if (link.includes('firefox-mpris'))
- return ' Firefox'
- return " File";
- }
- let url = link.replace(/(^\w+:|^)\/\//, '');
- let domain = url.match(/(?:[a-z]+\.)?([a-z]+\.[a-z]+)/i)[1];
- if (domain == 'ytimg.com') return ' Youtube';
- if (domain == 'discordapp.net') return ' Discord';
- if (domain == 'sndcdn.com') return ' SoundCloud';
- return domain;
-}
-
-const DEFAULT_MUSIC_FONT = 'Gabarito, sans-serif';
-function getTrackfont(player) {
- const title = player.trackTitle;
- const artists = player.trackArtists.join(' ');
- if (artists.includes('TANO*C') || artists.includes('USAO') || artists.includes('Kobaryo'))
- return 'Chakra Petch'; // Rigid square replacement
- if (title.includes('東方'))
- return 'Crimson Text, serif'; // Serif for Touhou stuff
- return DEFAULT_MUSIC_FONT;
-}
-function trimTrackTitle(title) {
- if (!title) return '';
- const cleanPatterns = [
- /【[^】]*】/, // Touhou n weeb stuff
- " [FREE DOWNLOAD]", // F-777
- ];
- cleanPatterns.forEach((expr) => title = title.replace(expr, ''));
- return title;
-}
-
-const TrackProgress = ({ player, ...rest }) => {
- const _updateProgress = (circprog) => {
- // const player = Mpris.getPlayer();
- if (!player) return;
- // Set circular progress (see definition of AnimatedCircProg for explanation)
- circprog.css = `font-size: ${Math.max(player.position / player.length * 100, 0)}px;`
- }
- return AnimatedCircProg({
- ...rest,
- className: 'osd-music-circprog',
- vpack: 'center',
- extraSetup: (self) => self
- .hook(Mpris, _updateProgress)
- .poll(3000, _updateProgress)
- ,
- })
-}
-
-const TrackTitle = ({ player, ...rest }) => Label({
- ...rest,
- label: 'No music playing',
- xalign: 0,
- truncate: 'end',
- // wrap: true,
- className: 'osd-music-title',
- setup: (self) => self.hook(player, (self) => {
- // Player name
- self.label = player.trackTitle.length > 0 ? trimTrackTitle(player.trackTitle) : 'No media';
- // Font based on track/artist
- const fontForThisTrack = getTrackfont(player);
- self.css = `font-family: ${fontForThisTrack}, ${DEFAULT_MUSIC_FONT};`;
- }, 'notify::track-title'),
-});
-
-const TrackArtists = ({ player, ...rest }) => Label({
- ...rest,
- xalign: 0,
- className: 'osd-music-artists',
- truncate: 'end',
- setup: (self) => self.hook(player, (self) => {
- self.label = player.trackArtists.length > 0 ? player.trackArtists.join(', ') : '';
- }, 'notify::track-artists'),
-})
-
-const CoverArt = ({ player, ...rest }) => {
- const fallbackCoverArt = Box({ // Fallback
- className: 'osd-music-cover-fallback',
- homogeneous: true,
- children: [Label({
- className: 'icon-material txt-gigantic txt-thin',
- label: 'music_note',
- })]
- });
- // const coverArtDrawingArea = Widget.DrawingArea({ className: 'osd-music-cover-art' });
- // const coverArtDrawingAreaStyleContext = coverArtDrawingArea.get_style_context();
- const realCoverArt = Box({
- className: 'osd-music-cover-art',
- homogeneous: true,
- // children: [coverArtDrawingArea],
- attribute: {
- 'pixbuf': null,
- // 'showImage': (self, imagePath) => {
- // const borderRadius = coverArtDrawingAreaStyleContext.get_property('border-radius', Gtk.StateFlags.NORMAL);
- // const frameHeight = coverArtDrawingAreaStyleContext.get_property('min-height', Gtk.StateFlags.NORMAL);
- // const frameWidth = coverArtDrawingAreaStyleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
- // let imageHeight = frameHeight;
- // let imageWidth = frameWidth;
- // // Get image dimensions
- // execAsync(['identify', '-format', '{"w":%w,"h":%h}', imagePath])
- // .then((output) => {
- // const imageDimensions = JSON.parse(output);
- // const imageAspectRatio = imageDimensions.w / imageDimensions.h;
- // const displayedAspectRatio = imageWidth / imageHeight;
- // if (imageAspectRatio >= displayedAspectRatio) {
- // imageWidth = imageHeight * imageAspectRatio;
- // } else {
- // imageHeight = imageWidth / imageAspectRatio;
- // }
- // // Real stuff
- // // TODO: fix memory leak(?)
- // // if (self.attribute.pixbuf) {
- // // self.attribute.pixbuf.unref();
- // // self.attribute.pixbuf = null;
- // // }
- // self.attribute.pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(imagePath, imageWidth, imageHeight);
-
- // coverArtDrawingArea.set_size_request(frameWidth, frameHeight);
- // coverArtDrawingArea.connect("draw", (widget, cr) => {
- // // Clip a rounded rectangle area
- // cr.arc(borderRadius, borderRadius, borderRadius, Math.PI, 1.5 * Math.PI);
- // cr.arc(frameWidth - borderRadius, borderRadius, borderRadius, 1.5 * Math.PI, 2 * Math.PI);
- // cr.arc(frameWidth - borderRadius, frameHeight - borderRadius, borderRadius, 0, 0.5 * Math.PI);
- // cr.arc(borderRadius, frameHeight - borderRadius, borderRadius, 0.5 * Math.PI, Math.PI);
- // cr.closePath();
- // cr.clip();
- // // Paint image as bg, centered
- // Gdk.cairo_set_source_pixbuf(cr, self.attribute.pixbuf,
- // frameWidth / 2 - imageWidth / 2,
- // frameHeight / 2 - imageHeight / 2
- // );
- // cr.paint();
- // });
- // }).catch(print)
- // },
- 'updateCover': (self) => {
- // const player = Mpris.getPlayer(); // Maybe no need to re-get player.. can't remember why I had this
- // Player closed
- // Note that cover path still remains, so we're checking title
- if (!player || player.trackTitle == "" || !player.coverPath) {
- self.css = `background-image: none;`; // CSS image
- App.applyCss(`${COMPILED_STYLE_DIR}/style.css`);
- return;
- }
-
- const coverPath = player.coverPath;
- const stylePath = `${player.coverPath}${darkMode.value ? '' : '-l'}${COVER_COLORSCHEME_SUFFIX}`;
- if (player.coverPath == lastCoverPath) { // Since 'notify::cover-path' emits on cover download complete
- Utils.timeout(200, () => {
- // self.attribute.showImage(self, coverPath);
- self.css = `background-image: url('${coverPath}');`; // CSS image
- });
- }
- lastCoverPath = player.coverPath;
-
- // If a colorscheme has already been generated, skip generation
- if (fileExists(stylePath)) {
- // self.attribute.showImage(self, coverPath)
- self.css = `background-image: url('${coverPath}');`; // CSS image
- App.applyCss(stylePath);
- return;
- }
-
- // Generate colors
- execAsync(['bash', '-c',
- `${App.configDir}/scripts/color_generation/generate_colors_material.py --path '${coverPath}' --mode ${darkMode.value ? 'dark' : 'light'} > ${GLib.get_user_state_dir()}/ags/scss/_musicmaterial.scss`])
- .then(() => {
- const dominantColor = `#${Utils.exec(`sh -c "magick '${coverPath}' -scale 1x1\\! -format '%[fx:int(255*r+.5)],%[fx:int(255*g+.5)],%[fx:int(255*b+.5)]' info: | sed 's/,/\\n/g' | xargs -L 1 printf '%02x' ; echo"`)}`
- // exec(`${App.configDir}/scripts/color_generation/pywal.sh -i "${player.coverPath}" -n -t -s -e -q ${darkMode.value ? '' : '-l'}`)
- // exec(`cp ${GLib.get_user_cache_dir()}/wal/colors.scss ${GLib.get_user_state_dir()}/ags/scss/_musicwal.scss`);
- exec(`cp '${App.configDir}/scripts/templates/wal/_musicwal.scss' '${GLib.get_user_state_dir()}/ags/scss/_musicwal.scss'`);
- exec(`sed -i 's/{{dominantColor}}/${dominantColor}/g' '${GLib.get_user_state_dir()}/ags/scss/_musicwal.scss'`)
- exec(`sed -i 's/{{backgroundColor}}/${darkMode.value ? "#0E1415" : "#EEF4F4"}/g' '${GLib.get_user_state_dir()}/ags/scss/_musicwal.scss'`)
- exec(`sed -i 's/{{foregroundColor}}/${darkMode.value ? "#EEF4F4" : "#0E1415"}/g' '${GLib.get_user_state_dir()}/ags/scss/_musicwal.scss'`)
-
- exec(`sass -I "${GLib.get_user_state_dir()}/ags/scss" -I "${App.configDir}/scss/fallback" "${App.configDir}/scss/_music.scss" "${stylePath}"`);
- Utils.timeout(200, () => {
- // self.attribute.showImage(self, coverPath)
- self.css = `background-image: url('${coverPath}');`; // CSS image
- });
- App.applyCss(`${stylePath}`);
- })
- .catch(print);
- },
- },
- setup: (self) => self
- .hook(player, (self) => {
- self.attribute.updateCover(self);
- }, 'notify::cover-path')
- ,
- });
- return Box({
- ...rest,
- className: 'osd-music-cover',
- children: [
- Widget.Overlay({
- child: fallbackCoverArt,
- overlays: [realCoverArt],
- })
- ],
- })
-}
-
-const TrackControls = ({ player, ...rest }) => Widget.Revealer({
- revealChild: false,
- transition: 'slide_right',
- transitionDuration: userOptions.animations.durationLarge,
- child: Widget.Box({
- ...rest,
- vpack: 'center',
- className: 'osd-music-controls spacing-h-3',
- children: [
- Button({
- className: 'osd-music-controlbtn',
- onClicked: () => player.previous(),
- child: Label({
- className: 'icon-material osd-music-controlbtn-txt',
- label: 'skip_previous',
- }),
- setup: setupCursorHover
- }),
- Button({
- className: 'osd-music-controlbtn',
- onClicked: () => player.next(),
- child: Label({
- className: 'icon-material osd-music-controlbtn-txt',
- label: 'skip_next',
- }),
- setup: setupCursorHover
- }),
- ],
- }),
- setup: (self) => self.hook(Mpris, (self) => {
- // const player = Mpris.getPlayer();
- if (!player)
- self.revealChild = false;
- else
- self.revealChild = true;
- }, 'notify::play-back-status'),
-});
-
-const TrackSource = ({ player, ...rest }) => Widget.Revealer({
- revealChild: false,
- transition: 'slide_left',
- transitionDuration: userOptions.animations.durationLarge,
- child: Widget.Box({
- ...rest,
- className: 'osd-music-pill spacing-h-5',
- homogeneous: true,
- children: [
- Label({
- hpack: 'fill',
- justification: 'center',
- className: 'icon-nerd',
- setup: (self) => self.hook(player, (self) => {
- self.label = detectMediaSource(player.trackCoverUrl);
- }, 'notify::cover-path'),
- }),
- ],
- }),
- setup: (self) => self.hook(Mpris, (self) => {
- const mpris = Mpris.getPlayer('');
- if (!mpris)
- self.revealChild = false;
- else
- self.revealChild = true;
- }),
-});
-
-const TrackTime = ({ player, ...rest }) => {
- return Widget.Revealer({
- revealChild: false,
- transition: 'slide_left',
- transitionDuration: userOptions.animations.durationLarge,
- child: Widget.Box({
- ...rest,
- vpack: 'center',
- className: 'osd-music-pill spacing-h-5',
- children: [
- Label({
- setup: (self) => self.poll(1000, (self) => {
- // const player = Mpris.getPlayer();
- if (!player) return;
- self.label = lengthStr(player.position);
- }),
- }),
- Label({ label: '/' }),
- Label({
- setup: (self) => self.hook(Mpris, (self) => {
- // const player = Mpris.getPlayer();
- if (!player) return;
- self.label = lengthStr(player.length);
- }),
- }),
- ],
- }),
- setup: (self) => self.hook(Mpris, (self) => {
- if (!player) self.revealChild = false;
- else self.revealChild = true;
- }),
- })
-}
-
-const PlayState = ({ player }) => {
- var position = 0;
- const trackCircProg = TrackProgress({ player: player });
- return Widget.Button({
- className: 'osd-music-playstate',
- child: Widget.Overlay({
- child: trackCircProg,
- overlays: [
- Widget.Button({
- className: 'osd-music-playstate-btn',
- onClicked: () => player.playPause(),
- child: Widget.Label({
- justification: 'center',
- hpack: 'fill',
- vpack: 'center',
- setup: (self) => self.hook(player, (label) => {
- label.label = `${player.playBackStatus == 'Playing' ? 'pause' : 'play_arrow'}`;
- }, 'notify::play-back-status'),
- }),
- setup: setupCursorHover
- }),
- ],
- passThrough: true,
- }),
- });
-}
-
-const MusicControlsWidget = (player) => Box({
- className: 'osd-music spacing-h-20 test',
- children: [
- CoverArt({ player: player, vpack: 'center' }),
- Box({
- vertical: true,
- className: 'spacing-v-5 osd-music-info',
- children: [
- Box({
- vertical: true,
- vpack: 'center',
- hexpand: true,
- children: [
- TrackTitle({ player: player }),
- TrackArtists({ player: player }),
- ]
- }),
- Box({ vexpand: true }),
- Box({
- className: 'spacing-h-10',
- setup: (box) => {
- box.pack_start(TrackControls({ player: player }), false, false, 0);
- box.pack_end(PlayState({ player: player }), false, false, 0);
- if(hasPlasmaIntegration || player.busName.startsWith('org.mpris.MediaPlayer2.chromium')) box.pack_end(TrackTime({ player: player }), false, false, 0)
- // box.pack_end(TrackSource({ vpack: 'center', player: player }), false, false, 0);
- }
- })
- ]
- })
- ]
-})
-
-export default () => Revealer({
- transition: 'slide_down',
- transitionDuration: userOptions.animations.durationLarge,
- revealChild: false,
- child: Box({
- children: Mpris.bind("players")
- .as(players => players.map((player) => (isRealPlayer(player) ? MusicControlsWidget(player) : null)))
- }),
- setup: (self) => self.hook(showMusicControls, (revealer) => {
- revealer.revealChild = showMusicControls.value;
- }),
-})
diff --git a/.config/ags/modules/indicators/notificationpopups.js b/.config/ags/modules/indicators/notificationpopups.js
deleted file mode 100644
index 0c38a670e..000000000
--- a/.config/ags/modules/indicators/notificationpopups.js
+++ /dev/null
@@ -1,45 +0,0 @@
-// This file is for popup notifications
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
-const { Box } = Widget;
-import Notification from '../.commonwidgets/notification.js';
-
-export default () => Box({
- vertical: true,
- hpack: 'center',
- className: 'osd-notifs spacing-v-5-revealer',
- attribute: {
- 'map': new Map(),
- 'dismiss': (box, id, force = false) => {
- if (!id || !box.attribute.map.has(id))
- return;
- const notifWidget = box.attribute.map.get(id);
- if (notifWidget == null || notifWidget.attribute.hovered && !force)
- return; // cuz already destroyed
-
- notifWidget.revealChild = false;
- notifWidget.attribute.destroyWithAnims();
- box.attribute.map.delete(id);
- },
- 'notify': (box, id) => {
- if (!id || Notifications.dnd) return;
- if (!Notifications.getNotification(id)) return;
-
- box.attribute.map.delete(id);
-
- const notif = Notifications.getNotification(id);
- const newNotif = Notification({
- notifObject: notif,
- isPopup: true,
- });
- box.attribute.map.set(id, newNotif);
- box.pack_end(box.attribute.map.get(id), false, false, 0);
- box.show_all();
- },
- },
- setup: (self) => self
- .hook(Notifications, (box, id) => box.attribute.notify(box, id), 'notified')
- .hook(Notifications, (box, id) => box.attribute.dismiss(box, id), 'dismissed')
- .hook(Notifications, (box, id) => box.attribute.dismiss(box, id, true), 'closed')
- ,
-});
diff --git a/.config/ags/modules/onscreenkeyboard/data_keyboardlayouts.js b/.config/ags/modules/onscreenkeyboard/data_keyboardlayouts.js
deleted file mode 100644
index 1a67b7a1f..000000000
--- a/.config/ags/modules/onscreenkeyboard/data_keyboardlayouts.js
+++ /dev/null
@@ -1,218 +0,0 @@
-// We're going to use ydotool
-// See /usr/include/linux/input-event-codes.h for keycodes
-
-export const DEFAULT_OSK_LAYOUT = "qwerty_full"
-export const oskLayouts = {
- qwerty_full: {
- name: "QWERTY - Full",
- name_short: "US",
- comment: "Like physical keyboard",
- // A key looks like this: { k: "a", ks: "A", t: "normal" } (key, key-shift, type)
- // key types are: normal, tab, caps, shift, control, fn (normal w/ half height), space, expand
- // keys: [
- // [{ k: "Esc", t: "fn" }, { k: "F1", t: "fn" }, { k: "F2", t: "fn" }, { k: "F3", t: "fn" }, { k: "F4", t: "fn" }, { k: "F5", t: "fn" }, { k: "F6", t: "fn" }, { k: "F7", t: "fn" }, { k: "F8", t: "fn" }, { k: "F9", t: "fn" }, { k: "F10", t: "fn" }, { k: "F11", t: "fn" }, { k: "F12", t: "fn" }, { k: "PrtSc", t: "fn" }, { k: "Del", t: "fn" }],
- // [{ k: "`", ks: "~", t: "normal" }, { k: "1", ks: "!", t: "normal" }, { k: "2", ks: "@", t: "normal" }, { k: "3", ks: "#", t: "normal" }, { k: "4", ks: "$", t: "normal" }, { k: "5", ks: "%", t: "normal" }, { k: "6", ks: "^", t: "normal" }, { k: "7", ks: "&", t: "normal" }, { k: "8", ks: "*", t: "normal" }, { k: "9", ks: "(", t: "normal" }, { k: "0", ks: ")", t: "normal" }, { k: "-", ks: "_", t: "normal" }, { k: "=", ks: "+", t: "normal" }, { k: "Backspace", t: "shift" }],
- // [{ k: "Tab", t: "tab" }, { k: "q", ks: "Q", t: "normal" }, { k: "w", ks: "W", t: "normal" }, { k: "e", ks: "E", t: "normal" }, { k: "r", ks: "R", t: "normal" }, { k: "t", ks: "T", t: "normal" }, { k: "y", ks: "Y", t: "normal" }, { k: "u", ks: "U", t: "normal" }, { k: "i", ks: "I", t: "normal" }, { k: "o", ks: "O", t: "normal" }, { k: "p", ks: "P", t: "normal" }, { k: "[", ks: "{", t: "normal" }, { k: "]", ks: "}", t: "normal" }, { k: "\\", ks: "|", t: "expand" }],
- // [{ k: "Caps", t: "caps" }, { k: "a", ks: "A", t: "normal" }, { k: "s", ks: "S", t: "normal" }, { k: "d", ks: "D", t: "normal" }, { k: "f", ks: "F", t: "normal" }, { k: "g", ks: "G", t: "normal" }, { k: "h", ks: "H", t: "normal" }, { k: "j", ks: "J", t: "normal" }, { k: "k", ks: "K", t: "normal" }, { k: "l", ks: "L", t: "normal" }, { k: ";", ks: ":", t: "normal" }, { k: "'", ks: '"', t: "normal" }, { k: "Enter", t: "expand" }],
- // [{ k: "Shift", t: "shift" }, { k: "z", ks: "Z", t: "normal" }, { k: "x", ks: "X", t: "normal" }, { k: "c", ks: "C", t: "normal" }, { k: "v", ks: "V", t: "normal" }, { k: "b", ks: "B", t: "normal" }, { k: "n", ks: "N", t: "normal" }, { k: "m", ks: "M", t: "normal" }, { k: ",", ks: "<", t: "normal" }, { k: ".", ks: ">", t: "normal" }, { k: "/", ks: "?", t: "normal" }, { k: "Shift", t: "expand" }],
- // [{ k: "Ctrl", t: "control" }, { k: "Fn", t: "normal" }, { k: "Win", t: "normal" }, { k: "Alt", t: "normal" }, { k: "Space", t: "space" }, { k: "Alt", t: "normal" }, { k: "Menu", t: "normal" }, { k: "Ctrl", t: "control" }]
- // ]
- // A normal key looks like this: {label: "a", labelShift: "A", shape: "normal", keycode: 30, type: "normal"}
- // A modkey looks like this: {label: "Ctrl", shape: "control", keycode: 29, type: "modkey"}
- // key types are: normal, tab, caps, shift, control, fn (normal w/ half height), space, expand
- keys: [
- [
- { keytype: "normal", label: "Esc", shape: "fn", keycode: 1 },
- { keytype: "normal", label: "F1", shape: "fn", keycode: 59 },
- { keytype: "normal", label: "F2", shape: "fn", keycode: 60 },
- { keytype: "normal", label: "F3", shape: "fn", keycode: 61 },
- { keytype: "normal", label: "F4", shape: "fn", keycode: 62 },
- { keytype: "normal", label: "F5", shape: "fn", keycode: 63 },
- { keytype: "normal", label: "F6", shape: "fn", keycode: 64 },
- { keytype: "normal", label: "F7", shape: "fn", keycode: 65 },
- { keytype: "normal", label: "F8", shape: "fn", keycode: 66 },
- { keytype: "normal", label: "F9", shape: "fn", keycode: 67 },
- { keytype: "normal", label: "F10", shape: "fn", keycode: 68 },
- { keytype: "normal", label: "F11", shape: "fn", keycode: 87 },
- { keytype: "normal", label: "F12", shape: "fn", keycode: 88 },
- { keytype: "normal", label: "PrtSc", shape: "fn", keycode: 99 },
- { keytype: "normal", label: "Del", shape: "fn", keycode: 111 }
- ],
- [
- { keytype: "normal", label: "`", labelShift: "~", shape: "normal", keycode: 41 },
- { keytype: "normal", label: "1", labelShift: "!", shape: "normal", keycode: 2 },
- { keytype: "normal", label: "2", labelShift: "@", shape: "normal", keycode: 3 },
- { keytype: "normal", label: "3", labelShift: "#", shape: "normal", keycode: 4 },
- { keytype: "normal", label: "4", labelShift: "$", shape: "normal", keycode: 5 },
- { keytype: "normal", label: "5", labelShift: "%", shape: "normal", keycode: 6 },
- { keytype: "normal", label: "6", labelShift: "^", shape: "normal", keycode: 7 },
- { keytype: "normal", label: "7", labelShift: "&", shape: "normal", keycode: 8 },
- { keytype: "normal", label: "8", labelShift: "*", shape: "normal", keycode: 9 },
- { keytype: "normal", label: "9", labelShift: "(", shape: "normal", keycode: 10 },
- { keytype: "normal", label: "0", labelShift: ")", shape: "normal", keycode: 11 },
- { keytype: "normal", label: "-", labelShift: "_", shape: "normal", keycode: 12 },
- { keytype: "normal", label: "=", labelShift: "+", shape: "normal", keycode: 13 },
- { keytype: "normal", label: "Backspace", shape: "expand", keycode: 14 }
- ],
- [
- { keytype: "normal", label: "Tab", shape: "tab", keycode: 15 },
- { keytype: "normal", label: "q", labelShift: "Q", shape: "normal", keycode: 16 },
- { keytype: "normal", label: "w", labelShift: "W", shape: "normal", keycode: 17 },
- { keytype: "normal", label: "e", labelShift: "E", shape: "normal", keycode: 18 },
- { keytype: "normal", label: "r", labelShift: "R", shape: "normal", keycode: 19 },
- { keytype: "normal", label: "t", labelShift: "T", shape: "normal", keycode: 20 },
- { keytype: "normal", label: "y", labelShift: "Y", shape: "normal", keycode: 21 },
- { keytype: "normal", label: "u", labelShift: "U", shape: "normal", keycode: 22 },
- { keytype: "normal", label: "i", labelShift: "I", shape: "normal", keycode: 23 },
- { keytype: "normal", label: "o", labelShift: "O", shape: "normal", keycode: 24 },
- { keytype: "normal", label: "p", labelShift: "P", shape: "normal", keycode: 25 },
- { keytype: "normal", label: "[", labelShift: "{", shape: "normal", keycode: 26 },
- { keytype: "normal", label: "]", labelShift: "}", shape: "normal", keycode: 27 },
- { keytype: "normal", label: "\\", labelShift: "|", shape: "expand", keycode: 43 }
- ],
- [
- //{ keytype: "normal", label: "Caps", shape: "caps", keycode: 58 }, // not needed as double-pressing shift does that
- { keytype: "spacer", label: "", shape: "empty" },
- { keytype: "spacer", label: "", shape: "empty" },
- { keytype: "normal", label: "a", labelShift: "A", shape: "normal", keycode: 30 },
- { keytype: "normal", label: "s", labelShift: "S", shape: "normal", keycode: 31 },
- { keytype: "normal", label: "d", labelShift: "D", shape: "normal", keycode: 32 },
- { keytype: "normal", label: "f", labelShift: "F", shape: "normal", keycode: 33 },
- { keytype: "normal", label: "g", labelShift: "G", shape: "normal", keycode: 34 },
- { keytype: "normal", label: "h", labelShift: "H", shape: "normal", keycode: 35 },
- { keytype: "normal", label: "j", labelShift: "J", shape: "normal", keycode: 36 },
- { keytype: "normal", label: "k", labelShift: "K", shape: "normal", keycode: 37 },
- { keytype: "normal", label: "l", labelShift: "L", shape: "normal", keycode: 38 },
- { keytype: "normal", label: ";", labelShift: ":", shape: "normal", keycode: 39 },
- { keytype: "normal", label: "'", labelShift: '"', shape: "normal", keycode: 40 },
- { keytype: "normal", label: "Enter", shape: "expand", keycode: 28 }
- ],
- [
- { keytype: "modkey", label: "Shift", labelShift: "Shift ⇧", labelCaps: "Locked ⇩", shape: "shift", keycode: 42 },
- { keytype: "normal", label: "z", labelShift: "Z", shape: "normal", keycode: 44 },
- { keytype: "normal", label: "x", labelShift: "X", shape: "normal", keycode: 45 },
- { keytype: "normal", label: "c", labelShift: "C", shape: "normal", keycode: 46 },
- { keytype: "normal", label: "v", labelShift: "V", shape: "normal", keycode: 47 },
- { keytype: "normal", label: "b", labelShift: "B", shape: "normal", keycode: 48 },
- { keytype: "normal", label: "n", labelShift: "N", shape: "normal", keycode: 49 },
- { keytype: "normal", label: "m", labelShift: "M", shape: "normal", keycode: 50 },
- { keytype: "normal", label: ",", labelShift: "<", shape: "normal", keycode: 51 },
- { keytype: "normal", label: ".", labelShift: ">", shape: "normal", keycode: 52 },
- { keytype: "normal", label: "/", labelShift: "?", shape: "normal", keycode: 53 },
- { keytype: "modkey", label: "Shift", labelShift: "Shift ⇧", labelCaps: "Locked ⇩", shape: "expand", keycode: 54 } // optional
- ],
- [
- { keytype: "modkey", label: "Ctrl", shape: "control", keycode: 29 },
- // { label: "Super", shape: "normal", keycode: 125 }, // dangerous
- { keytype: "modkey", label: "Alt", shape: "normal", keycode: 56 },
- { keytype: "normal", label: "Space", shape: "space", keycode: 57 },
- { keytype: "modkey", label: "Alt", shape: "normal", keycode: 100 },
- // { label: "Super", shape: "normal", keycode: 126 }, // dangerous
- { keytype: "normal", label: "Menu", shape: "normal", keycode: 139 },
- { keytype: "modkey", label: "Ctrl", shape: "control", keycode: 97 }
- ]
- ]
- },
- qwertz_full: {
- name: "QWERTZ - Full",
- name_short: "DE",
- comment: "Keyboard layout commonly used in German-speaking countries",
- keys: [
- [
- { keytype: "normal", label: "Esc", shape: "fn", keycode: 1 },
- { keytype: "normal", label: "F1", shape: "fn", keycode: 59 },
- { keytype: "normal", label: "F2", shape: "fn", keycode: 60 },
- { keytype: "normal", label: "F3", shape: "fn", keycode: 61 },
- { keytype: "normal", label: "F4", shape: "fn", keycode: 62 },
- { keytype: "normal", label: "F5", shape: "fn", keycode: 63 },
- { keytype: "normal", label: "F6", shape: "fn", keycode: 64 },
- { keytype: "normal", label: "F7", shape: "fn", keycode: 65 },
- { keytype: "normal", label: "F8", shape: "fn", keycode: 66 },
- { keytype: "normal", label: "F9", shape: "fn", keycode: 67 },
- { keytype: "normal", label: "F10", shape: "fn", keycode: 68 },
- { keytype: "normal", label: "F11", shape: "fn", keycode: 87 },
- { keytype: "normal", label: "F12", shape: "fn", keycode: 88 },
- { keytype: "normal", label: "Druck", shape: "fn", keycode: 99 },
- { keytype: "normal", label: "Entf", shape: "fn", keycode: 111 }
- ],
- [
- { keytype: "normal", label: "^", labelShift: "°", labelAlt: "′", shape: "normal", keycode: 41 },
- { keytype: "normal", label: "1", labelShift: "!", labelAlt: "¹", shape: "normal", keycode: 2 },
- { keytype: "normal", label: "2", labelShift: "\"", labelAlt: "²", shape: "normal", keycode: 3 },
- { keytype: "normal", label: "3", labelShift: "§", labelAlt: "³", shape: "normal", keycode: 4 },
- { keytype: "normal", label: "4", labelShift: "$", labelAlt: "¼", shape: "normal", keycode: 5 },
- { keytype: "normal", label: "5", labelShift: "%", labelAlt: "½", shape: "normal", keycode: 6 },
- { keytype: "normal", label: "6", labelShift: "&", labelAlt: "¬", shape: "normal", keycode: 7 },
- { keytype: "normal", label: "7", labelShift: "/", labelAlt: "{", shape: "normal", keycode: 8 },
- { keytype: "normal", label: "8", labelShift: "(", labelAlt: "[", shape: "normal", keycode: 9 },
- { keytype: "normal", label: "9", labelShift: ")", labelAlt: "]", shape: "normal", keycode: 10 },
- { keytype: "normal", label: "0", labelShift: "=", labelAlt: "}", shape: "normal", keycode: 11 },
- { keytype: "normal", label: "ß", labelShift: "?", labelAlt: "\\", shape: "normal", keycode: 12 },
- { keytype: "normal", label: "´", labelShift: "`", labelAlt: "¸", shape: "normal", keycode: 13 },
- { keytype: "normal", label: "⟵", shape: "expand", keycode: 14 }
- ],
- [
- { keytype: "normal", label: "Tab ⇆", shape: "tab", keycode: 15 },
- { keytype: "normal", label: "q", labelShift: "Q", labelAlt: "@", shape: "normal", keycode: 16 },
- { keytype: "normal", label: "w", labelShift: "W", labelAlt: "ſ", shape: "normal", keycode: 17 },
- { keytype: "normal", label: "e", labelShift: "E", labelAlt: "€", shape: "normal", keycode: 18 },
- { keytype: "normal", label: "r", labelShift: "R", labelAlt: "¶", shape: "normal", keycode: 19 },
- { keytype: "normal", label: "t", labelShift: "T", labelAlt: "ŧ", shape: "normal", keycode: 20 },
- { keytype: "normal", label: "z", labelShift: "Z", labelAlt: "←", shape: "normal", keycode: 21 },
- { keytype: "normal", label: "u", labelShift: "U", labelAlt: "↓", shape: "normal", keycode: 22 },
- { keytype: "normal", label: "i", labelShift: "I", labelAlt: "→", shape: "normal", keycode: 23 },
- { keytype: "normal", label: "o", labelShift: "O", labelAlt: "ø", shape: "normal", keycode: 24 },
- { keytype: "normal", label: "p", labelShift: "P", labelAlt: "þ", shape: "normal", keycode: 25 },
- { keytype: "normal", label: "ü", labelShift: "Ü", labelAlt: "¨", shape: "normal", keycode: 26 },
- { keytype: "normal", label: "+", labelShift: "*", labelAlt: "~", shape: "normal", keycode: 27 },
- { keytype: "normal", label: "↵", shape: "expand", keycode: 28 }
- ],
- [
- //{ keytype: "normal", label: "Umschalt ⇩", shape: "caps", keycode: 58 },
- { keytype: "spacer", label: "", shape: "empty" },
- { keytype: "spacer", label: "", shape: "empty" },
- { keytype: "normal", label: "a", labelShift: "A", labelAlt: "æ", shape: "normal", keycode: 30 },
- { keytype: "normal", label: "s", labelShift: "S", labelAlt: "ſ", shape: "normal", keycode: 31 },
- { keytype: "normal", label: "d", labelShift: "D", labelAlt: "ð", shape: "normal", keycode: 32 },
- { keytype: "normal", label: "f", labelShift: "F", labelAlt: "đ", shape: "normal", keycode: 33 },
- { keytype: "normal", label: "g", labelShift: "G", labelAlt: "ŋ", shape: "normal", keycode: 34 },
- { keytype: "normal", label: "h", labelShift: "H", labelAlt: "ħ", shape: "normal", keycode: 35 },
- { keytype: "normal", label: "j", labelShift: "J", labelAlt: "", shape: "normal", keycode: 36 },
- { keytype: "normal", label: "k", labelShift: "K", labelAlt: "ĸ", shape: "normal", keycode: 37 },
- { keytype: "normal", label: "l", labelShift: "L", labelAlt: "ł", shape: "normal", keycode: 38 },
- { keytype: "normal", label: "ö", labelShift: "Ö", labelAlt: "˝", shape: "normal", keycode: 39 },
- { keytype: "normal", label: "ä", labelShift: 'Ä', labelAlt: "^", shape: "normal", keycode: 40 },
- { keytype: "normal", label: "#", labelShift: '\'', labelAlt: "’", shape: "normal", keycode: 43 },
- { keytype: "spacer", label: "", shape: "empty" },
- //{ keytype: "normal", label: "↵", shape: "expand", keycode: 28 }
- ],
- [
- { keytype: "modkey", label: "Shift", labelShift: "Shift ⇧", labelCaps: "Locked ⇩", shape: "shift", keycode: 42 },
- { keytype: "normal", label: "<", labelShift: ">", labelAlt: "|", shape: "normal", keycode: 86 },
- { keytype: "normal", label: "y", labelShift: "Y", labelAlt: "»", shape: "normal", keycode: 44 },
- { keytype: "normal", label: "x", labelShift: "X", labelAlt: "«", shape: "normal", keycode: 45 },
- { keytype: "normal", label: "c", labelShift: "C", labelAlt: "¢", shape: "normal", keycode: 46 },
- { keytype: "normal", label: "v", labelShift: "V", labelAlt: "„", shape: "normal", keycode: 47 },
- { keytype: "normal", label: "b", labelShift: "B", labelAlt: "“", shape: "normal", keycode: 48 },
- { keytype: "normal", label: "n", labelShift: "N", labelAlt: "”", shape: "normal", keycode: 49 },
- { keytype: "normal", label: "m", labelShift: "M", labelAlt: "µ", shape: "normal", keycode: 50 },
- { keytype: "normal", label: ",", labelShift: ";", labelAlt: "·", shape: "normal", keycode: 51 },
- { keytype: "normal", label: ".", labelShift: ":", labelAlt: "…", shape: "normal", keycode: 52 },
- { keytype: "normal", label: "-", labelShift: "_", labelAlt: "–", shape: "normal", keycode: 53 },
- { keytype: "modkey", label: "Shift", labelShift: "Shift ⇧", labelCaps: "Locked ⇩", shape: "expand", keycode: 54 }, // optional
- ],
- [
- { keytype: "modkey", label: "Strg", shape: "control", keycode: 29 },
- //{ keytype: "normal", label: "", shape: "normal", keycode: 125 }, // dangerous
- { keytype: "modkey", label: "Alt", shape: "normal", keycode: 56 },
- { keytype: "normal", label: "Leertaste", shape: "space", keycode: 57 },
- { keytype: "modkey", label: "Alt Gr", shape: "normal", keycode: 100 },
- // { label: "Super", shape: "normal", keycode: 126 }, // dangerous
- //{ keytype: "normal", label: "Menu", shape: "normal", keycode: 139 }, // doesn't work?
- { keytype: "modkey", label: "Strg", shape: "control", keycode: 97 },
- { keytype: "normal", label: "⇦", shape: "normal", keycode: 105 },
- { keytype: "normal", label: "⇨", shape: "normal", keycode: 106 },
- ]
- ]
- }
-}
\ No newline at end of file
diff --git a/.config/ags/modules/onscreenkeyboard/main.js b/.config/ags/modules/onscreenkeyboard/main.js
deleted file mode 100644
index 2204ebf35..000000000
--- a/.config/ags/modules/onscreenkeyboard/main.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import PopupWindow from '../.widgethacks/popupwindow.js';
-import OnScreenKeyboard from "./onscreenkeyboard.js";
-
-export default (id) => PopupWindow({
- monitor: id,
- anchor: ['bottom'],
- name: `osk${id}`,
- showClassName: 'osk-show',
- hideClassName: 'osk-hide',
- child: OnScreenKeyboard({ id: id }),
-});
diff --git a/.config/ags/modules/onscreenkeyboard/onscreenkeyboard.js b/.config/ags/modules/onscreenkeyboard/onscreenkeyboard.js
deleted file mode 100644
index 79da3ee5d..000000000
--- a/.config/ags/modules/onscreenkeyboard/onscreenkeyboard.js
+++ /dev/null
@@ -1,267 +0,0 @@
-const { Gtk } = imports.gi;
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-
-const { Box, EventBox, Button, Revealer } = Widget;
-const { execAsync } = Utils;
-import { MaterialIcon } from '../.commonwidgets/materialicon.js';
-import { DEFAULT_OSK_LAYOUT, oskLayouts } from './data_keyboardlayouts.js';
-import { setupCursorHoverGrab } from '../.widgetutils/cursorhover.js';
-
-const keyboardLayout = oskLayouts[userOptions.onScreenKeyboard.layout] ? userOptions.onScreenKeyboard.layout : DEFAULT_OSK_LAYOUT;
-const keyboardJson = oskLayouts[keyboardLayout];
-
-async function startYdotoolIfNeeded() {
- const running = exec('pidof ydotool')
- if (!running) execAsync(['ydotoold']).catch(print);
-}
-
-function releaseAllKeys() {
- const keycodes = Array.from(Array(249).keys());
- execAsync([`ydotool`, `key`, ...keycodes.map(keycode => `${keycode}:0`)])
- .then(console.log('[OSK] Released all keys'))
- .catch(print);
-}
-class ShiftMode {
- static Off = new ShiftMode('Off');
- static Normal = new ShiftMode('Normal');
- static Locked = new ShiftMode('Locked');
-
- constructor(name) {
- this.name = name;
- }
- toString() {
- return `ShiftMode.${this.name}`;
- }
-}
-var modsPressed = false;
-
-const TopDecor = () => Box({
- vertical: true,
- children: [
- Box({
- hpack: 'center',
- className: 'osk-dragline',
- homogeneous: true,
- children: [EventBox({
- setup: setupCursorHoverGrab,
- })]
- })
- ]
-});
-
-const KeyboardControlButton = (icon, text, runFunction) => Button({
- className: 'osk-control-button spacing-h-10',
- onClicked: () => runFunction(),
- child: Widget.Box({
- children: [
- MaterialIcon(icon, 'norm'),
- Widget.Label({
- label: `${text}`,
- }),
- ]
- })
-})
-
-const KeyboardControls = () => Box({
- vertical: true,
- className: 'spacing-v-5',
- children: [
- Button({
- className: 'osk-control-button txt-norm icon-material',
- onClicked: () => {
- releaseAllKeys();
- toggleWindowOnAllMonitors('osk');
- },
- label: 'keyboard_hide',
- }),
- Button({
- className: 'osk-control-button txt-norm',
- label: `${keyboardJson['name_short']}`,
- }),
- Button({
- className: 'osk-control-button txt-norm icon-material',
- onClicked: () => { // TODO: Proper clipboard widget, since fuzzel doesn't receive mouse inputs
- execAsync([`bash`, `-c`, "pkill fuzzel || cliphist list | fuzzel --match-mode fzf --dmenu | cliphist decode | wl-copy"]).catch(print);
- },
- label: 'assignment',
- }),
- ]
-})
-
-var shiftMode = ShiftMode.Off;
-var shiftButton;
-var rightShiftButton;
-var allButtons = [];
-const KeyboardItself = (kbJson) => {
- return Box({
- vertical: true,
- className: 'spacing-v-5',
- children: kbJson.keys.map(row => Box({
- vertical: false,
- className: 'spacing-h-5',
- children: row.map(key => {
- return Button({
- className: `osk-key osk-key-${key.shape}`,
- hexpand: ["space", "expand"].includes(key.shape),
- label: key.label,
- attribute:
- { key: key },
- setup: (button) => {
- let pressed = false;
- allButtons = allButtons.concat(button);
- if (key.keytype == "normal") {
- button.connect('pressed', () => { // mouse down
- execAsync(`ydotool key ${key.keycode}:1`).catch(print);
- });
- button.connect('clicked', () => { // release
- execAsync(`ydotool key ${key.keycode}:0`).catch(print);
-
- if (shiftMode == ShiftMode.Normal) {
- shiftMode = ShiftMode.Off;
- if (typeof shiftButton !== 'undefined') {
- execAsync(`ydotool key 42:0`).catch(print);
- shiftButton.toggleClassName('osk-key-active', false);
- }
- if (typeof rightShiftButton !== 'undefined') {
- execAsync(`ydotool key 54:0`).catch(print);
- rightShiftButton.toggleClassName('osk-key-active', false);
- }
- allButtons.forEach(button => {
- if (typeof button.attribute.key.labelShift !== 'undefined') button.label = button.attribute.key.label;
- })
- }
- });
- }
- else if (key.keytype == "modkey") {
- button.connect('pressed', () => { // release
- if (pressed) {
- execAsync(`ydotool key ${key.keycode}:0`).catch(print);
- button.toggleClassName('osk-key-active', false);
- pressed = false;
- if (key.keycode == 100) { // Alt Gr button
- allButtons.forEach(button => { if (typeof button.attribute.key.labelAlt !== 'undefined') button.label = button.attribute.key.label; });
- }
- }
- else {
- execAsync(`ydotool key ${key.keycode}:1`).catch(print);
- button.toggleClassName('osk-key-active', true);
- if (!(key.keycode == 42 || key.keycode == 54)) pressed = true;
- else switch (shiftMode.name) { // This toggles the shift button state
- case "Off": {
- shiftMode = ShiftMode.Normal;
- allButtons.forEach(button => { if (typeof button.attribute.key.labelShift !== 'undefined') button.label = button.attribute.key.labelShift; })
- if (typeof shiftButton !== 'undefined') {
- shiftButton.toggleClassName('osk-key-active', true);
- }
- if (typeof rightShiftButton !== 'undefined') {
- rightShiftButton.toggleClassName('osk-key-active', true);
- }
- } break;
- case "Normal": {
- shiftMode = ShiftMode.Locked;
- if (typeof shiftButton !== 'undefined') shiftButton.label = key.labelCaps;
- if (typeof rightShiftButton !== 'undefined') rightShiftButton.label = key.labelCaps;
- } break;
- case "Locked": {
- shiftMode = ShiftMode.Off;
- if (typeof shiftButton !== 'undefined') {
- shiftButton.label = key.label;
- shiftButton.toggleClassName('osk-key-active', false);
- }
- if (typeof rightShiftButton !== 'undefined') {
- rightShiftButton.label = key.label;
- rightShiftButton.toggleClassName('osk-key-active', false);
- }
- execAsync(`ydotool key ${key.keycode}:0`).catch(print);
-
- allButtons.forEach(button => { if (typeof button.attribute.key.labelShift !== 'undefined') button.label = button.attribute.key.label; }
- )
- };
- }
- if (key.keycode == 100) { // Alt Gr button
- allButtons.forEach(button => { if (typeof button.attribute.key.labelAlt !== 'undefined') button.label = button.attribute.key.labelAlt; });
- }
- modsPressed = true;
- }
- });
- if (key.keycode == 42) shiftButton = button;
- else if (key.keycode == 54) rightShiftButton = button;
- }
- }
- })
- })
- }))
- })
-}
-
-const KeyboardWindow = () => Box({
- vexpand: true,
- hexpand: true,
- vertical: true,
- className: 'osk-window spacing-v-5',
- children: [
- TopDecor(),
- Box({
- className: 'osk-body spacing-h-10',
- children: [
- KeyboardControls(),
- Widget.Box({ className: 'separator-line' }),
- KeyboardItself(keyboardJson),
- ],
- })
- ],
- setup: (self) => self.hook(App, (self, name, visible) => { // Update on open
- if (!name) return;
- if (name.startsWith('osk') && visible) {
- self.setCss(`margin-bottom: -0px;`);
- }
- }),
-});
-
-export default ({ id }) => {
- const kbWindow = KeyboardWindow();
- const gestureEvBox = EventBox({ child: kbWindow })
- const gesture = Gtk.GestureDrag.new(gestureEvBox);
- gesture.connect('drag-begin', async () => {
- try {
- const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
- Hyprland.messageAsync('j/cursorpos').then((out) => {
- gesture.startY = JSON.parse(out).y;
- }).catch(print);
- } catch {
- return;
- }
- });
- gesture.connect('drag-update', async () => {
- try {
- const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
- Hyprland.messageAsync('j/cursorpos').then((out) => {
- const currentY = JSON.parse(out).y;
- const offset = gesture.startY - currentY;
-
- if (offset > 0) return;
-
- kbWindow.setCss(`
- margin-bottom: ${offset}px;
- `);
- }).catch(print);
- } catch {
- return;
- }
- });
- gesture.connect('drag-end', () => {
- var offset = gesture.get_offset()[2];
- if (offset > 50) {
- App.closeWindow(`osk${id}`);
- }
- else {
- kbWindow.setCss(`
- transition: margin-bottom 170ms cubic-bezier(0.05, 0.7, 0.1, 1);
- margin-bottom: 0px;
- `);
- }
- })
- return gestureEvBox;
-};
diff --git a/.config/ags/modules/overview/actions.js b/.config/ags/modules/overview/actions.js
deleted file mode 100644
index 766cf4542..000000000
--- a/.config/ags/modules/overview/actions.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
-
-function moveClientToWorkspace(address, workspace) {
- Utils.execAsync(['bash', '-c', `hyprctl dispatch movetoworkspacesilent ${workspace},address:${address} &`]);
-}
-
-export function dumpToWorkspace(from, to) {
- if (from == to) return;
- Hyprland.clients.forEach(client => {
- if (client.workspace.id == from) {
- moveClientToWorkspace(client.address, to);
- }
- });
-}
-
-export function swapWorkspace(workspaceA, workspaceB) {
- if (workspaceA == workspaceB) return;
- const clientsA = [];
- const clientsB = [];
- Hyprland.clients.forEach(client => {
- if (client.workspace.id == workspaceA) clientsA.push(client.address);
- if (client.workspace.id == workspaceB) clientsB.push(client.address);
- });
-
- clientsA.forEach((address) => moveClientToWorkspace(address, workspaceB));
- clientsB.forEach((address) => moveClientToWorkspace(address, workspaceA));
-}
\ No newline at end of file
diff --git a/.config/ags/modules/overview/main.js b/.config/ags/modules/overview/main.js
deleted file mode 100644
index 19118d922..000000000
--- a/.config/ags/modules/overview/main.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import { SearchAndWindows } from "./windowcontent.js";
-import PopupWindow from '../.widgethacks/popupwindow.js';
-import { clickCloseRegion } from '../.commonwidgets/clickcloseregion.js';
-
-export default (id = '') => PopupWindow({
- name: `overview${id}`,
- // exclusivity: 'ignore',
- keymode: 'on-demand',
- visible: false,
- anchor: ['top', 'bottom', 'left', 'right'],
- layer: 'top',
- child: Widget.Box({
- vertical: true,
- children: [
- clickCloseRegion({ name: 'overview', multimonitor: false, expand: false }),
- Widget.Box({
- children: [
- clickCloseRegion({ name: 'overview', multimonitor: false }),
- SearchAndWindows(),
- clickCloseRegion({ name: 'overview', multimonitor: false }),
- ]
- }),
- clickCloseRegion({ name: 'overview', multimonitor: false }),
- ]
- }),
-})
-
diff --git a/.config/ags/modules/overview/miscfunctions.js b/.config/ags/modules/overview/miscfunctions.js
deleted file mode 100644
index 196f5a7f0..000000000
--- a/.config/ags/modules/overview/miscfunctions.js
+++ /dev/null
@@ -1,146 +0,0 @@
-const { Gio, GLib } = imports.gi;
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { execAsync, exec } = Utils;
-import Todo from "../../services/todo.js";
-
-export function hasUnterminatedBackslash(inputString) {
- // Use a regular expression to match a trailing odd number of backslashes
- const regex = /\\+$/;
- return regex.test(inputString);
-}
-
-export function launchCustomCommand(command) {
- const args = command.toLowerCase().split(' ');
- if (args[0] == '>raw') { // Mouse raw input
- Utils.execAsync('hyprctl -j getoption input:accel_profile')
- .then((output) => {
- const value = JSON.parse(output)["str"].trim();
- if (value != "[[EMPTY]]" && value != "") {
- execAsync(['bash', '-c', `hyprctl keyword input:accel_profile '[[EMPTY]]'`]).catch(print);
- }
- else {
- execAsync(['bash', '-c', `hyprctl keyword input:accel_profile flat`]).catch(print);
- }
- })
- }
- else if (args[0] == '>img') { // Change wallpaper
- execAsync([`bash`, `-c`, `${App.configDir}/scripts/color_generation/switchwall.sh`, `&`]).catch(print);
- }
- else if (args[0] == '>color') { // Generate colorscheme from color picker
- if (!args[1])
- execAsync([`bash`, `-c`, `${App.configDir}/scripts/color_generation/switchcolor.sh --pick`, `&`]).catch(print);
- else if (args[1][0] === '#')
- execAsync([`bash`, `-c`, `${App.configDir}/scripts/color_generation/switchcolor.sh "${args[1]}"`, `&`]).catch(print);
- }
- else if (args[0] == '>light') { // Light mode
- darkMode.setValue(false).catch(print);
- }
- else if (args[0] == '>dark') { // Dark mode
- darkMode.setValue(true).catch(print);
- }
- else if (args[0] == '>badapple') { // Black and white
- execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_state_dir()}/ags/user && sed -i "3s/.*/monochrome/" ${GLib.get_user_state_dir()}/ags/user/colormode.txt`])
- .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchcolor.sh`]))
- .catch(print);
- }
- else if (args[0] == '>material') { // Use material colors
- execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_state_dir()}/ags/user && echo "material" > ${GLib.get_user_state_dir()}/ags/user/colorbackend.txt`]).catch(print)
- .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchwall.sh --noswitch`]).catch(print))
- .catch(print);
- }
- else if (args[0] == '>todo') { // Todo
- Todo.add(args.slice(1).join(' '));
- }
- else if (args[0] == '>shutdown') { // Shut down
- execAsync([`bash`, `-c`, `systemctl poweroff || loginctl poweroff`]).catch(print);
- }
- else if (args[0] == '>reboot') { // Reboot
- execAsync([`bash`, `-c`, `systemctl reboot || loginctl reboot`]).catch(print);
- }
- else if (args[0] == '>sleep') { // Sleep
- execAsync([`bash`, `-c`, `systemctl suspend || loginctl suspend`]).catch(print);
- }
- else if (args[0] == '>logout') { // Log out
- execAsync([`bash`, `-c`, `pkill Hyprland || pkill sway`]).catch(print);
- }
-}
-
-export function execAndClose(command, terminal) {
- App.closeWindow('overview');
- if (terminal) {
- execAsync([`bash`, `-c`, `${userOptions.apps.terminal} fish -C "${command}"`, `&`]).catch(print);
- }
- else
- execAsync(command).catch(print);
-}
-
-export function couldBeMath(str) {
- const regex = /^[0-9.+*/-]/;
- return regex.test(str);
-}
-
-export function expandTilde(path) {
- if (path.startsWith('~')) {
- return GLib.get_home_dir() + path.slice(1);
- } else {
- return path;
- }
-}
-
-function getFileIcon(fileInfo) {
- let icon = fileInfo.get_icon();
- if (icon) {
- // Get the icon's name
- return icon.get_names()[0];
- } else {
- // Default icon for files
- return 'text-x-generic';
- }
-}
-
-export function ls({ path = '~', silent = false }) {
- let contents = [];
- try {
- let expandedPath = expandTilde(path);
- if (expandedPath.endsWith('/'))
- expandedPath = expandedPath.slice(0, -1);
- let folder = Gio.File.new_for_path(expandedPath);
-
- let enumerator = folder.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
- let fileInfo;
- while ((fileInfo = enumerator.next_file(null)) !== null) {
- let fileName = fileInfo.get_display_name();
- let fileType = fileInfo.get_file_type();
-
- let item = {
- parentPath: expandedPath,
- name: fileName,
- type: fileType === Gio.FileType.DIRECTORY ? 'folder' : 'file',
- icon: getFileIcon(fileInfo),
- };
-
- // Add file extension for files
- if (fileType === Gio.FileType.REGULAR) {
- let fileExtension = fileName.split('.').pop();
- item.type = `${fileExtension}`;
- }
-
- contents.push(item);
- contents.sort((a, b) => {
- const aIsFolder = a.type.startsWith('folder');
- const bIsFolder = b.type.startsWith('folder');
- if (aIsFolder && !bIsFolder) {
- return -1;
- } else if (!aIsFolder && bIsFolder) {
- return 1;
- } else {
- return a.name.localeCompare(b.name); // Sort alphabetically within folders and files
- }
- });
- }
- } catch (e) {
- if (!silent) console.log(e);
- }
- return contents;
-}
diff --git a/.config/ags/modules/overview/overview_hyprland.js b/.config/ags/modules/overview/overview_hyprland.js
deleted file mode 100644
index dae007aca..000000000
--- a/.config/ags/modules/overview/overview_hyprland.js
+++ /dev/null
@@ -1,446 +0,0 @@
-// TODO
-// - Make client destroy/create not destroy and recreate the whole thing
-// - Active ws hook optimization: only update when moving to next group
-//
-const { Gdk, Gtk } = imports.gi;
-const { Gravity } = imports.gi.Gdk;
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Variable from 'resource:///com/github/Aylur/ags/variable.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-
-import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
-const { execAsync, exec } = Utils;
-import { setupCursorHoverGrab } from '../.widgetutils/cursorhover.js';
-import { dumpToWorkspace, swapWorkspace } from "./actions.js";
-import { iconExists, substitute } from "../.miscutils/icons.js";
-import { monitors } from '../.commondata/hyprlanddata.js';
-import { MaterialIcon } from '../.commonwidgets/materialicon.js';
-
-const NUM_OF_WORKSPACES_SHOWN = userOptions.overview.numOfCols * userOptions.overview.numOfRows;
-const TARGET = [Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags.SAME_APP, 0)];
-
-const overviewTick = Variable(false);
-const overviewMonitor = Variable(0);
-
-export default () => {
- const clientMap = new Map();
- const ContextMenuWorkspaceArray = ({ label, actionFunc, thisWorkspace }) => Widget.MenuItem({
- label: `${label}`,
- setup: (menuItem) => {
- let submenu = new Gtk.Menu();
- submenu.className = 'menu';
-
- const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
- const startWorkspace = offset + 1;
- const endWorkspace = startWorkspace + NUM_OF_WORKSPACES_SHOWN - 1;
- for (let i = startWorkspace; i <= endWorkspace; i++) {
- let button = new Gtk.MenuItem({
- label: `Workspace ${i}`
- });
- button.connect("activate", () => {
- // execAsync([`${onClickBinary}`, `${thisWorkspace}`, `${i}`]).catch(print);
- actionFunc(thisWorkspace, i);
- overviewTick.setValue(!overviewTick.value);
- });
- submenu.append(button);
- }
- menuItem.set_reserve_indicator(true);
- menuItem.set_submenu(submenu);
- }
- })
-
- const Window = ({ address, at: [x, y], size: [w, h], workspace: { id, name }, class: c, initialClass, monitor, title, xwayland }, screenCoords) => {
- const revealInfoCondition = (Math.min(w, h) * userOptions.overview.scale > 70);
- if (w <= 0 || h <= 0 || (c === '' && title === '')) return null;
- // Non-primary monitors
- if (screenCoords.x != 0) x -= screenCoords.x;
- if (screenCoords.y != 0) y -= screenCoords.y;
- // Other offscreen adjustments
- if (x + w <= 0) x += (Math.floor(x / monitors[monitor].width) * monitors[monitor].width);
- else if (x < 0) { w = x + w; x = 0; }
- if (y + h <= 0) x += (Math.floor(y / monitors[monitor].height) * monitors[monitor].height);
- else if (y < 0) { h = y + h; y = 0; }
- // Prevents throwing an error when multiple monitors are plugged in but only one is enabled (#1047)
- if (monitors.length - 1 < monitor) {
- monitor = monitors.length - 1;
- }
- // Properly scale for multi monitors
- w *= monitors[overviewMonitor.value].width / monitors[monitor].width;
- h *= monitors[overviewMonitor.value].height / monitors[monitor].height;
- // Truncate if offscreen
- if (x + w > monitors[overviewMonitor.value].width) w = monitors[overviewMonitor.value].width - x;
- if (y + h > monitors[overviewMonitor.value].height) h = monitors[overviewMonitor.value].height - y;
-
- if (c.length == 0) c = initialClass;
- const iconName = substitute(c);
- // const appIcon = iconExists(iconName) ? Widget.Icon({
- // icon: iconName,
- // size: Math.min(w, h) * userOptions.overview.scale / 2.5,
- // }) : MaterialIcon('terminal', 'gigantic', {
- // css: `font-size: ${Math.min(w, h) * userOptions.overview.scale / 2.5}px`,
- // });
- const appIcon = Widget.Icon({
- icon: iconName,
- size: Math.min(w, h) * userOptions.overview.scale / 2.5,
- });
- return Widget.Button({
- attribute: {
- address, x, y, w, h, ws: id,
- updateIconSize: (self) => {
- appIcon.size = Math.min(self.attribute.w, self.attribute.h) * userOptions.overview.scale / 2.5;
- },
- },
- className: 'overview-tasks-window',
- hpack: 'start',
- vpack: 'start',
- css: `
- margin-left: ${Math.round(x * userOptions.overview.scale)}px;
- margin-top: ${Math.round(y * userOptions.overview.scale)}px;
- margin-right: -${Math.round((x + w) * userOptions.overview.scale)}px;
- margin-bottom: -${Math.round((y + h) * userOptions.overview.scale)}px;
- `,
- onClicked: (self) => {
- Hyprland.messageAsync(`dispatch focuswindow address:${address}`);
- App.closeWindow('overview');
- },
- onMiddleClickRelease: () => Hyprland.messageAsync(`dispatch closewindow address:${address}`),
- onSecondaryClick: (button) => {
- button.toggleClassName('overview-tasks-window-selected', true);
- const menu = Widget.Menu({
- className: 'menu',
- children: [
- Widget.MenuItem({
- child: Widget.Label({
- xalign: 0,
- label: "Close (Middle-click)",
- }),
- onActivate: () => Hyprland.messageAsync(`dispatch closewindow address:${address}`),
- }),
- ContextMenuWorkspaceArray({
- label: "Dump windows to workspace",
- actionFunc: dumpToWorkspace,
- thisWorkspace: Number(id)
- }),
- ContextMenuWorkspaceArray({
- label: "Swap windows with workspace",
- actionFunc: swapWorkspace,
- thisWorkspace: Number(id)
- }),
- ],
- });
- menu.connect("deactivate", () => {
- button.toggleClassName('overview-tasks-window-selected', false);
- })
- menu.connect("selection-done", () => {
- button.toggleClassName('overview-tasks-window-selected', false);
- })
- menu.popup_at_widget(button.get_parent(), Gravity.SOUTH, Gravity.NORTH, null); // Show menu below the button
- button.connect("destroy", () => menu.destroy());
- },
- child: Widget.Box({
- homogeneous: true,
- child: Widget.Box({
- vertical: true,
- vpack: 'center',
- children: [
- appIcon,
- // TODO: Add xwayland tag instead of just having italics
- Widget.Revealer({
- transition: 'slide_right',
- revealChild: revealInfoCondition,
- child: Widget.Revealer({
- transition: 'slide_down',
- revealChild: revealInfoCondition,
- child: Widget.Label({
- maxWidthChars: 1, // Doesn't matter what number
- truncate: 'end',
- className: `margin-top-5 ${xwayland ? 'txt txt-italic' : 'txt'}`,
- css: overviewMonitor.bind().as(monitor => `
- font-size: ${Math.min(monitors[monitor].width, monitors[monitor].height) * userOptions.overview.scale / 14.6}px;
- margin: 0px ${Math.min(monitors[monitor].width, monitors[monitor].height) * userOptions.overview.scale / 10}px;
- `),
- // If the title is too short, include the class
- label: (title.length <= 1 ? `${c}: ${title}` : title),
- })
- })
- })
- ]
- })
- }),
- tooltipText: `${c}: ${title}`,
- setup: (button) => {
- setupCursorHoverGrab(button);
-
- button.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, TARGET, Gdk.DragAction.MOVE);
- button.drag_source_set_icon_name(substitute(c));
-
- button.connect('drag-begin', (button) => { // On drag start, add the dragging class
- button.toggleClassName('overview-tasks-window-dragging', true);
- });
- button.connect('drag-data-get', (_w, _c, data) => { // On drag finish, give address
- data.set_text(address, address.length);
- button.toggleClassName('overview-tasks-window-dragging', false);
- });
- },
- });
- }
-
- const Workspace = (index) => {
- // const fixed = Widget.Fixed({
- // attribute: {
- // put: (widget, x, y) => {
- // fixed.put(widget, x, y);
- // },
- // move: (widget, x, y) => {
- // fixed.move(widget, x, y);
- // },
- // }
- // });
- const fixed = Widget.Box({
- attribute: {
- put: (widget, x, y) => {
- if (!widget.attribute) return;
- // Note: x and y are already multiplied by userOptions.overview.scale
- const newCss = `
- margin-left: ${Math.round(x)}px;
- margin-top: ${Math.round(y)}px;
- margin-right: -${Math.round(x + (widget.attribute.w * userOptions.overview.scale))}px;
- margin-bottom: -${Math.round(y + (widget.attribute.h * userOptions.overview.scale))}px;
- `;
- widget.css = newCss;
- fixed.pack_start(widget, false, false, 0);
- },
- move: (widget, x, y) => {
- if (!widget) return;
- if (!widget.attribute) return;
- // Note: x and y are already multiplied by userOptions.overview.scale
- const newCss = `
- margin-left: ${Math.round(x)}px;
- margin-top: ${Math.round(y)}px;
- margin-right: -${Math.round(x + (widget.attribute.w * userOptions.overview.scale))}px;
- margin-bottom: -${Math.round(y + (widget.attribute.h * userOptions.overview.scale))}px;
- `;
- widget.css = newCss;
- },
- }
- })
- const WorkspaceNumber = ({ index, ...rest }) => Widget.Label({
- className: 'overview-tasks-workspace-number',
- label: `${index}`,
- css: overviewMonitor.bind().as(monitor => `
- margin: ${Math.min(monitors[monitor].width, monitors[monitor].height) * userOptions.overview.scale * userOptions.overview.wsNumMarginScale}px;
- font-size: ${monitors[monitor].height * userOptions.overview.scale * userOptions.overview.wsNumScale}px;
- `),
- setup: (self) => self.hook(Hyprland.active.workspace, (self) => {
- // Update when going to new ws group
- const currentGroup = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN);
- self.label = `${currentGroup * NUM_OF_WORKSPACES_SHOWN + index}`;
- }),
- ...rest,
- })
- const widget = Widget.Box({
- className: 'overview-tasks-workspace',
- vpack: 'center',
- // Rounding and adding 1px to minimum width/height to work around scaling inaccuracy:
- css: overviewMonitor.bind().as(monitor => `
- min-width: ${1 + Math.round(monitors[monitor].width * userOptions.overview.scale)}px;
- min-height: ${1 + Math.round(monitors[monitor].height * userOptions.overview.scale)}px;
- `),
- children: [Widget.EventBox({
- hexpand: true,
- onPrimaryClick: () => {
- Hyprland.messageAsync(`dispatch workspace ${index}`);
- App.closeWindow('overview');
- },
- setup: (eventbox) => {
- eventbox.drag_dest_set(Gtk.DestDefaults.ALL, TARGET, Gdk.DragAction.COPY);
- eventbox.connect('drag-data-received', (_w, _c, _x, _y, data) => {
- const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
- Hyprland.messageAsync(`dispatch movetoworkspacesilent ${index + offset},address:${data.get_text()}`)
- overviewTick.setValue(!overviewTick.value);
- });
- },
- child: Widget.Overlay({
- child: Widget.Box({}),
- overlays: [
- WorkspaceNumber({ index: index, hpack: 'start', vpack: 'start' }),
- fixed
- ]
- }),
- })],
- });
- const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
- fixed.attribute.put(WorkspaceNumber(offset + index), 0, 0);
- widget.clear = () => {
- const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
- clientMap.forEach((client, address) => {
- if (!client) return;
- if ((client.attribute.ws <= offset || client.attribute.ws > offset + NUM_OF_WORKSPACES_SHOWN) ||
- (client.attribute.ws == offset + index)) {
- client.destroy();
- client = null;
- clientMap.delete(address);
- }
- });
- }
- widget.set = (clientJson, screenCoords) => {
- let c = clientMap.get(clientJson.address);
- if (c) {
- if (c.attribute?.ws !== clientJson.workspace.id) {
- c.destroy();
- c = null;
- clientMap.delete(clientJson.address);
- }
- else if (c) {
- c.attribute.w = clientJson.size[0];
- c.attribute.h = clientJson.size[1];
- c.attribute.updateIconSize(c);
- fixed.attribute.move(c,
- Math.max(0, clientJson.at[0] * userOptions.overview.scale),
- Math.max(0, clientJson.at[1] * userOptions.overview.scale)
- );
- return;
- }
- }
- const newWindow = Window(clientJson, screenCoords);
- if (newWindow === null) return;
- // clientMap.set(clientJson.address, newWindow);
- fixed.attribute.put(newWindow,
- Math.max(0, newWindow.attribute.x * userOptions.overview.scale),
- Math.max(0, newWindow.attribute.y * userOptions.overview.scale)
- );
- clientMap.set(clientJson.address, newWindow);
- };
- widget.unset = (clientAddress) => {
- const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
- let c = clientMap.get(clientAddress);
- if (!c) return;
- c.destroy();
- c = null;
- clientMap.delete(clientAddress);
- };
- widget.show = () => {
- fixed.show_all();
- }
- return widget;
- };
-
- const arr = (s, n) => {
- const array = [];
- for (let i = 0; i < n; i++)
- array.push(s + i);
-
- return array;
- };
-
- const OverviewRow = ({ startWorkspace, workspaces, windowName = 'overview' }) => Widget.Box({
- children: arr(startWorkspace, workspaces).map(Workspace),
- attribute: {
- workspaceGroup: Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN),
- monitorMap: [],
- getMonitorMap: (box) => {
- execAsync('hyprctl -j monitors').then(monitors => {
- box.attribute.monitorMap = JSON.parse(monitors).reduce((acc, item) => {
- acc[item.id] = { x: item.x, y: item.y };
- return acc;
- }, {});
- });
- },
- update: (box) => {
- const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
- Hyprland.messageAsync('j/clients').then(clients => {
- const allClients = JSON.parse(clients);
- const kids = box.get_children();
- kids.forEach(kid => kid.clear());
- for (let i = 0; i < allClients.length; i++) {
- const client = allClients[i];
- const childID = client.workspace.id - (offset + startWorkspace);
- if (offset + startWorkspace <= client.workspace.id &&
- client.workspace.id <= offset + startWorkspace + workspaces) {
- const screenCoords = box.attribute.monitorMap[client.monitor];
- if (kids[childID]) {
- kids[childID].set(client, screenCoords);
- }
- continue;
- }
- }
- kids.forEach(kid => kid.show());
- }).catch(print);
- },
- updateWorkspace: (box, id) => {
- const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
- if (!( // Not in range, ignore
- offset + startWorkspace <= id &&
- id <= offset + startWorkspace + workspaces
- )) return;
- // if (!App.getWindow(windowName)?.visible) return;
- Hyprland.messageAsync('j/clients').then(clients => {
- const allClients = JSON.parse(clients);
- const kids = box.get_children();
- for (let i = 0; i < allClients.length; i++) {
- const client = allClients[i];
- if (client.workspace.id != id) continue;
- const screenCoords = box.attribute.monitorMap[client.monitor];
- kids[id - (offset + startWorkspace)]?.set(client, screenCoords);
- }
- kids[id - (offset + startWorkspace)]?.show();
- }).catch(print);
- },
- },
- setup: (box) => {
- box.attribute.getMonitorMap(box);
- box
- .hook(overviewTick, (box) => box.attribute.update(box))
- .hook(Hyprland, (box, clientAddress) => {
- const offset = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN) * NUM_OF_WORKSPACES_SHOWN;
- const kids = box.get_children();
- const client = Hyprland.getClient(clientAddress);
- if (!client) return;
- const id = client.workspace.id;
-
- box.attribute.updateWorkspace(box, id);
- kids[id - (offset + startWorkspace)]?.unset(clientAddress);
- }, 'client-removed')
- .hook(Hyprland, (box, clientAddress) => {
- const client = Hyprland.getClient(clientAddress);
- if (!client) return;
- box.attribute.updateWorkspace(box, client.workspace.id);
- }, 'client-added')
- .hook(Hyprland.active.workspace, (box) => {
- // Full update when going to new ws group
- const previousGroup = box.attribute.workspaceGroup;
- const currentGroup = Math.floor((Hyprland.active.workspace.id - 1) / NUM_OF_WORKSPACES_SHOWN);
- if (currentGroup !== previousGroup) {
- if (!App.getWindow(windowName) || !App.getWindow(windowName).visible) return;
- box.attribute.update(box);
- box.attribute.workspaceGroup = currentGroup;
- }
- })
- .hook(App, (box, name, visible) => { // Update on open
- if (name == 'overview' && visible) {
- overviewMonitor.value = Hyprland.active.monitor.id;
- box.attribute.update(box);
- }
- })
- },
- });
-
- return Widget.Revealer({
- revealChild: true,
- // hpack to prevent unneeded expansion in overview-tasks-workspace:
- hpack: 'center',
- transition: 'slide_down',
- transitionDuration: userOptions.animations.durationLarge,
- child: Widget.Box({
- vertical: true,
- className: 'overview-tasks',
- children: Array.from({ length: userOptions.overview.numOfRows }, (_, index) =>
- OverviewRow({
- startWorkspace: 1 + index * userOptions.overview.numOfCols,
- workspaces: userOptions.overview.numOfCols,
- })
- )
- }),
- });
-}
diff --git a/.config/ags/modules/overview/searchbuttons.js b/.config/ags/modules/overview/searchbuttons.js
deleted file mode 100644
index 58f516076..000000000
--- a/.config/ags/modules/overview/searchbuttons.js
+++ /dev/null
@@ -1,189 +0,0 @@
-const { Gtk } = imports.gi;
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { execAsync, exec } = Utils;
-import { searchItem } from './searchitem.js';
-import { execAndClose, couldBeMath, launchCustomCommand } from './miscfunctions.js';
-import GeminiService from '../../services/gemini.js';
-
-export const NoResultButton = () => searchItem({
- materialIconName: 'Error',
- name: "Search invalid",
- content: "No results found!",
- onActivate: () => {
- App.closeWindow('overview');
- },
-});
-
-export const DirectoryButton = ({ parentPath, name, type, icon }) => {
- const actionText = Widget.Revealer({
- revealChild: false,
- transition: "crossfade",
- transitionDuration: userOptions.animations.durationLarge,
- child: Widget.Label({
- className: 'overview-search-results-txt txt txt-small txt-action',
- label: 'Open',
- })
- });
- const actionTextRevealer = Widget.Revealer({
- revealChild: false,
- transition: "slide_left",
- transitionDuration: userOptions.animations.durationSmall,
- child: actionText,
- });
- return Widget.Button({
- className: 'overview-search-result-btn',
- onClicked: () => {
- App.closeWindow('overview');
- execAsync(['bash', '-c', `xdg-open '${parentPath}/${name}'`, `&`]).catch(print);
- },
- child: Widget.Box({
- children: [
- Widget.Box({
- vertical: false,
- children: [
- Widget.Box({
- className: 'overview-search-results-icon',
- homogeneous: true,
- child: Widget.Icon({
- icon: icon,
- }),
- }),
- Widget.Label({
- className: 'overview-search-results-txt txt txt-norm',
- label: name,
- }),
- Widget.Box({ hexpand: true }),
- actionTextRevealer,
- ]
- })
- ]
- }),
- setup: (self) => self
- .on('focus-in-event', (button) => {
- actionText.revealChild = true;
- actionTextRevealer.revealChild = true;
- })
- .on('focus-out-event', (button) => {
- actionText.revealChild = false;
- actionTextRevealer.revealChild = false;
- })
- ,
- })
-}
-
-export const CalculationResultButton = ({ result, text }) => searchItem({
- materialIconName: 'calculate',
- name: `Math result`,
- actionName: "Copy",
- content: `${result}`,
- onActivate: () => {
- App.closeWindow('overview');
- execAsync(['wl-copy', `${result}`]).catch(print);
- },
-});
-
-export const DesktopEntryButton = (app) => {
- const actionText = Widget.Revealer({
- revealChild: false,
- transition: "crossfade",
- transitionDuration: userOptions.animations.durationLarge,
- child: Widget.Label({
- className: 'overview-search-results-txt txt txt-small txt-action',
- label: 'Launch',
- })
- });
- const actionTextRevealer = Widget.Revealer({
- revealChild: false,
- transition: "slide_left",
- transitionDuration: userOptions.animations.durationSmall,
- child: actionText,
- });
- return Widget.Button({
- className: 'overview-search-result-btn',
- onClicked: () => {
- App.closeWindow('overview');
- app.launch();
- },
- child: Widget.Box({
- children: [
- Widget.Box({
- vertical: false,
- children: [
- Widget.Box({
- className: 'overview-search-results-icon',
- homogeneous: true,
- child: Widget.Icon({
- icon: app.iconName,
- }),
- }),
- Widget.Label({
- className: 'overview-search-results-txt txt txt-norm',
- label: app.name,
- }),
- Widget.Box({ hexpand: true }),
- actionTextRevealer,
- ]
- })
- ]
- }),
- setup: (self) => self
- .on('focus-in-event', (button) => {
- actionText.revealChild = true;
- actionTextRevealer.revealChild = true;
- })
- .on('focus-out-event', (button) => {
- actionText.revealChild = false;
- actionTextRevealer.revealChild = false;
- })
- ,
- })
-}
-
-export const ExecuteCommandButton = ({ command, terminal = false }) => searchItem({
- materialIconName: `${terminal ? 'terminal' : 'settings_b_roll'}`,
- name: `Run command`,
- actionName: `Execute ${terminal ? 'in terminal' : ''}`,
- content: `${command}`,
- onActivate: () => execAndClose(command, terminal),
- extraClassName: 'techfont',
-})
-
-export const CustomCommandButton = ({ text = '' }) => searchItem({
- materialIconName: 'settings_suggest',
- name: 'Action',
- actionName: 'Run',
- content: `${text}`,
- onActivate: () => {
- App.closeWindow('overview');
- launchCustomCommand(text);
- },
-});
-
-export const SearchButton = ({ text = '' }) => searchItem({
- materialIconName: 'travel_explore',
- name: 'Search the web',
- actionName: 'Go',
- content: `${text}`,
- onActivate: () => {
- App.closeWindow('overview');
- let search = userOptions.search.engineBaseUrl + text;
- for (let site of userOptions.search.excludedSites) {
- if (site) search += ` -site:${site}`;
- }
- execAsync(['bash', '-c', `xdg-open '${search}' &`]).catch(print);
- },
-});
-
-export const AiButton = ({ text }) => searchItem({
- materialIconName: 'chat_paste_go',
- name: 'Ask Gemini',
- actionName: 'Ask',
- content: `${text}`,
- onActivate: () => {
- GeminiService.send(text);
- App.closeWindow('overview');
- App.openWindow('sideleft');
- },
-});
diff --git a/.config/ags/modules/overview/searchitem.js b/.config/ags/modules/overview/searchitem.js
deleted file mode 100644
index 2a3303a48..000000000
--- a/.config/ags/modules/overview/searchitem.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-
-export const searchItem = ({ materialIconName, name, actionName, content, onActivate, extraClassName = '', ...rest }) => {
- const actionText = Widget.Revealer({
- revealChild: false,
- transition: "crossfade",
- transitionDuration: userOptions.animations.durationLarge,
- child: Widget.Label({
- className: 'overview-search-results-txt txt txt-small txt-action',
- label: `${actionName}`,
- })
- });
- const actionTextRevealer = Widget.Revealer({
- revealChild: false,
- transition: "slide_left",
- transitionDuration: userOptions.animations.durationSmall,
- child: actionText,
- })
- return Widget.Button({
- className: `overview-search-result-btn txt ${extraClassName}`,
- onClicked: onActivate,
- child: Widget.Box({
- children: [
- Widget.Box({
- vertical: false,
- children: [
- Widget.Label({
- className: `icon-material overview-search-results-icon`,
- label: `${materialIconName}`,
- }),
- Widget.Box({
- vertical: true,
- children: [
- Widget.Label({
- hpack: 'start',
- className: 'overview-search-results-txt txt-smallie txt-subtext',
- label: `${name}`,
- truncate: "end",
- }),
- Widget.Label({
- hpack: 'start',
- className: 'overview-search-results-txt txt-norm',
- label: `${content}`,
- truncate: "end",
- }),
- ]
- }),
- Widget.Box({ hexpand: true }),
- actionTextRevealer,
- ],
- })
- ]
- }),
- setup: (self) => self
- .on('focus-in-event', (button) => {
- actionText.revealChild = true;
- actionTextRevealer.revealChild = true;
- })
- .on('focus-out-event', (button) => {
- actionText.revealChild = false;
- actionTextRevealer.revealChild = false;
- })
- ,
- });
-}
diff --git a/.config/ags/modules/overview/windowcontent.js b/.config/ags/modules/overview/windowcontent.js
deleted file mode 100644
index 23e839395..000000000
--- a/.config/ags/modules/overview/windowcontent.js
+++ /dev/null
@@ -1,213 +0,0 @@
-const { Gdk, Gtk } = imports.gi;
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-
-import Applications from 'resource:///com/github/Aylur/ags/service/applications.js';
-const { execAsync, exec } = Utils;
-import { execAndClose, expandTilde, hasUnterminatedBackslash, couldBeMath, launchCustomCommand, ls } from './miscfunctions.js';
-import {
- CalculationResultButton, CustomCommandButton, DirectoryButton,
- DesktopEntryButton, ExecuteCommandButton, SearchButton, AiButton, NoResultButton,
-} from './searchbuttons.js';
-import { checkKeybind } from '../.widgetutils/keybind.js';
-import GeminiService from '../../services/gemini.js';
-
-// Add math funcs
-const { abs, sin, cos, tan, cot, asin, acos, atan, acot } = Math;
-const pi = Math.PI;
-// trigonometric funcs for deg
-const sind = x => sin(x * pi / 180);
-const cosd = x => cos(x * pi / 180);
-const tand = x => tan(x * pi / 180);
-const cotd = x => cot(x * pi / 180);
-const asind = x => asin(x) * 180 / pi;
-const acosd = x => acos(x) * 180 / pi;
-const atand = x => atan(x) * 180 / pi;
-const acotd = x => acot(x) * 180 / pi;
-
-const MAX_RESULTS = 10;
-const OVERVIEW_SCALE = 0.18; // = overview workspace box / screen size
-const OVERVIEW_WS_NUM_SCALE = 0.09;
-const OVERVIEW_WS_NUM_MARGIN_SCALE = 0.07;
-const TARGET = [Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags.SAME_APP, 0)];
-
-function iconExists(iconName) {
- let iconTheme = Gtk.IconTheme.get_default();
- return iconTheme.has_icon(iconName);
-}
-
-const OptionalOverview = async () => {
- try {
- return (await import('./overview_hyprland.js')).default();
- } catch {
- return Widget.Box({});
- // return (await import('./overview_hyprland.js')).default();
- }
-};
-
-const overviewContent = await OptionalOverview();
-
-export const SearchAndWindows = () => {
- var _appSearchResults = [];
-
- const resultsBox = Widget.Box({
- className: 'overview-search-results',
- vertical: true,
- });
- const resultsRevealer = Widget.Revealer({
- transitionDuration: userOptions.animations.durationLarge,
- revealChild: false,
- transition: 'slide_down',
- // duration: 200,
- hpack: 'center',
- child: resultsBox,
- });
- const entryPromptRevealer = Widget.Revealer({
- transition: 'crossfade',
- transitionDuration: userOptions.animations.durationLarge,
- revealChild: true,
- hpack: 'center',
- child: Widget.Label({
- className: 'overview-search-prompt txt-small txt',
- label: getString('Type to search')
- }),
- });
-
- const entryIconRevealer = Widget.Revealer({
- transition: 'crossfade',
- transitionDuration: userOptions.animations.durationLarge,
- revealChild: false,
- hpack: 'end',
- child: Widget.Label({
- className: 'txt txt-large icon-material overview-search-icon',
- label: 'search',
- }),
- });
-
- const entryIcon = Widget.Box({
- className: 'overview-search-prompt-box',
- setup: box => box.pack_start(entryIconRevealer, true, true, 0),
- });
-
- const entry = Widget.Entry({
- className: 'overview-search-box txt-small txt',
- hpack: 'center',
- onAccept: (self) => { // This is when you hit Enter
- resultsBox.children[0].onClicked();
- },
- onChange: (entry) => { // this is when you type
- const isAction = entry.text[0] == '>';
- const isDir = (['/', '~'].includes(entry.text[0]));
- resultsBox.get_children().forEach(ch => ch.destroy());
-
- // check empty if so then dont do stuff
- if (entry.text == '') {
- resultsRevealer.revealChild = false;
- overviewContent.revealChild = true;
- entryPromptRevealer.revealChild = true;
- entryIconRevealer.revealChild = false;
- entry.toggleClassName('overview-search-box-extended', false);
- return;
- }
- const text = entry.text;
- resultsRevealer.revealChild = true;
- overviewContent.revealChild = false;
- entryPromptRevealer.revealChild = false;
- entryIconRevealer.revealChild = true;
- entry.toggleClassName('overview-search-box-extended', true);
- _appSearchResults = Applications.query(text);
-
- // Calculate
- if (userOptions.search.enableFeatures.mathResults && couldBeMath(text)) { // Eval on typing is dangerous; this is a small workaround.
- try {
- const fullResult = eval(text.replace(/\^/g, "**"));
- resultsBox.add(CalculationResultButton({ result: fullResult, text: text }));
- } catch (e) {
- // console.log(e);
- }
- }
- if (userOptions.search.enableFeatures.directorySearch && isDir) {
- var contents = [];
- contents = ls({ path: text, silent: true });
- contents.forEach((item) => {
- resultsBox.add(DirectoryButton(item));
- })
- }
- if (userOptions.search.enableFeatures.actions && isAction) { // Eval on typing is dangerous, this is a workaround.
- resultsBox.add(CustomCommandButton({ text: entry.text }));
- }
- // Add application entries
- let appsToAdd = MAX_RESULTS;
- _appSearchResults.forEach(app => {
- if (appsToAdd == 0) return;
- resultsBox.add(DesktopEntryButton(app));
- appsToAdd--;
- });
-
- // Fallbacks
- // if the first word is an actual command
- if (userOptions.search.enableFeatures.commands && !isAction && !hasUnterminatedBackslash(text) && exec(`bash -c "command -v ${text.split(' ')[0]}"`) != '') {
- resultsBox.add(ExecuteCommandButton({ command: entry.text, terminal: entry.text.startsWith('sudo') }));
- }
-
- // Add fallback: search
- if (userOptions.search.enableFeatures.aiSearch)
- resultsBox.add(AiButton({ text: entry.text }));
- if (userOptions.search.enableFeatures.webSearch)
- resultsBox.add(SearchButton({ text: entry.text }));
- if (resultsBox.children.length == 0) resultsBox.add(NoResultButton());
- resultsBox.show_all();
- },
- });
- return Widget.Box({
- vertical: true,
- children: [
- Widget.Box({
- hpack: 'center',
- children: [
- entry,
- Widget.Box({
- className: 'overview-search-icon-box',
- setup: (box) => {
- box.pack_start(entryPromptRevealer, true, true, 0)
- },
- }),
- entryIcon,
- ]
- }),
- overviewContent,
- resultsRevealer,
- ],
- setup: (self) => self
- .hook(App, (_b, name, visible) => {
- if (name == 'overview' && !visible) {
- resultsBox.children = [];
- entry.set_text('');
- }
- })
- .on('key-press-event', (widget, event) => { // Typing
- const keyval = event.get_keyval()[1];
- const modstate = event.get_state()[1];
- if (checkKeybind(event, userOptions.keybinds.overview.altMoveLeft))
- entry.set_position(Math.max(entry.get_position() - 1, 0));
- else if (checkKeybind(event, userOptions.keybinds.overview.altMoveRight))
- entry.set_position(Math.min(entry.get_position() + 1, entry.get_text().length));
- else if (checkKeybind(event, userOptions.keybinds.overview.deleteToEnd)) {
- const text = entry.get_text();
- const pos = entry.get_position();
- const newText = text.slice(0, pos);
- entry.set_text(newText);
- entry.set_position(newText.length);
- }
- else if (!(modstate & Gdk.ModifierType.CONTROL_MASK)) { // Ctrl not held
- if (keyval >= 32 && keyval <= 126 && widget != entry) {
- Utils.timeout(1, () => entry.grab_focus());
- entry.set_text(entry.text + String.fromCharCode(keyval));
- entry.set_position(-1);
- }
- }
- })
- ,
- });
-};
diff --git a/.config/ags/modules/screencorners/main.js b/.config/ags/modules/screencorners/main.js
deleted file mode 100644
index 83e09c0b4..000000000
--- a/.config/ags/modules/screencorners/main.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
-import { enableClickthrough } from "../.widgetutils/clickthrough.js";
-import { RoundedCorner } from "../.commonwidgets/cairo_roundedcorner.js";
-
-if(userOptions.appearance.fakeScreenRounding === 2) Hyprland.connect('event', (service, name, data) => {
- if (name == 'fullscreen') {
- const monitor = Hyprland.active.monitor.id;
- if (data == '1') {
- for (const window of App.windows) {
- if (window.name.startsWith("corner") && window.name.endsWith(monitor)) {
- App.closeWindow(window.name);
- }
- }
- } else {
- for (const window of App.windows) {
- if (window.name.startsWith("corner") && window.name.endsWith(monitor)) {
- App.openWindow(window.name);
- }
- }
- }
- }
-})
-
-export default (monitor = 0, where = 'bottom left', useOverlayLayer = true) => {
- const positionString = where.replace(/\s/, ""); // remove space
- return Widget.Window({
- monitor,
- name: `corner${positionString}${monitor}`,
- layer: useOverlayLayer ? 'overlay' : 'top',
- anchor: where.split(' '),
- exclusivity: 'ignore',
- visible: true,
- child: RoundedCorner(positionString, { className: 'corner-black', }),
- setup: enableClickthrough,
- });
-}
-
diff --git a/.config/ags/modules/session/main.js b/.config/ags/modules/session/main.js
deleted file mode 100644
index 30c5ab6f4..000000000
--- a/.config/ags/modules/session/main.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import SessionScreen from "./sessionscreen.js";
-import PopupWindow from '../.widgethacks/popupwindow.js';
-
-export default (id = 0) => PopupWindow({ // On-screen keyboard
- monitor: id,
- name: `session${id}`,
- visible: false,
- keymode: 'on-demand',
- layer: 'overlay',
- exclusivity: 'ignore',
- anchor: ['top', 'bottom', 'left', 'right'],
- child: SessionScreen({ id: id }),
-})
diff --git a/.config/ags/modules/session/sessionscreen.js b/.config/ags/modules/session/sessionscreen.js
deleted file mode 100644
index 007878b6e..000000000
--- a/.config/ags/modules/session/sessionscreen.js
+++ /dev/null
@@ -1,134 +0,0 @@
-// This is for the cool memory indicator on the sidebar
-// For the right pill of the bar, see system.js
-const { Gdk, Gtk } = imports.gi;
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-import { monitors } from '../.commondata/hyprlanddata.js';
-
-const { exec, execAsync } = Utils;
-
-const SessionButton = (name, icon, command, props = {}, colorid = 0) => {
- const buttonDescription = Widget.Revealer({
- vpack: 'end',
- transitionDuration: userOptions.animations.durationSmall,
- transition: 'slide_down',
- revealChild: false,
- child: Widget.Label({
- className: 'txt-smaller session-button-desc',
- label: name,
- }),
- });
- return Widget.Button({
- onClicked: command,
- className: `session-button session-color-${colorid}`,
- child: Widget.Overlay({
- className: 'session-button-box',
- child: Widget.Label({
- vexpand: true,
- className: 'icon-material',
- label: icon,
- }),
- overlays: [
- buttonDescription,
- ]
- }),
- onHover: (button) => {
- const display = Gdk.Display.get_default();
- const cursor = Gdk.Cursor.new_from_name(display, 'pointer');
- button.get_window().set_cursor(cursor);
- buttonDescription.revealChild = true;
- },
- onHoverLost: (button) => {
- const display = Gdk.Display.get_default();
- const cursor = Gdk.Cursor.new_from_name(display, 'default');
- button.get_window().set_cursor(cursor);
- buttonDescription.revealChild = false;
- },
- setup: (self) => self
- .on('focus-in-event', (self) => {
- buttonDescription.revealChild = true;
- self.toggleClassName('session-button-focused', true);
- })
- .on('focus-out-event', (self) => {
- buttonDescription.revealChild = false;
- self.toggleClassName('session-button-focused', false);
- })
- ,
- ...props,
- });
-}
-
-export default ({ id = 0 }) => {
- // lock, logout, sleep
- const lockButton = SessionButton(getString('Lock'), 'lock', () => { closeWindowOnAllMonitors('session'); execAsync(['loginctl', 'lock-session']).catch(print) }, {}, 1);
- const logoutButton = SessionButton(getString('Logout'), 'logout', () => { closeWindowOnAllMonitors('session'); execAsync(['bash', '-c', 'pkill Hyprland || pkill sway || pkill niri || loginctl terminate-user $USER']).catch(print) }, {}, 2);
- const sleepButton = SessionButton(getString('Sleep'), 'sleep', () => { closeWindowOnAllMonitors('session'); execAsync(['bash', '-c', 'systemctl suspend || loginctl suspend']).catch(print) }, {}, 3);
- // hibernate, shutdown, reboot
- const hibernateButton = SessionButton(getString('Hibernate'), 'downloading', () => { closeWindowOnAllMonitors('session'); execAsync(['bash', '-c', 'systemctl hibernate || loginctl hibernate']).catch(print) }, {}, 4);
- const shutdownButton = SessionButton(getString('Shutdown'), 'power_settings_new', () => { closeWindowOnAllMonitors('session'); execAsync(['bash', '-c', 'systemctl poweroff || loginctl poweroff']).catch(print) }, {}, 5);
- const rebootButton = SessionButton(getString('Reboot'), 'restart_alt', () => { closeWindowOnAllMonitors('session'); execAsync(['bash', '-c', 'systemctl reboot || loginctl reboot']).catch(print) }, {}, 6);
- const cancelButton = SessionButton(getString('Cancel'), 'close', () => closeWindowOnAllMonitors('session'), { className: 'session-button-cancel' }, 7);
-
- const sessionDescription = Widget.Box({
- vertical: true,
- css: 'margin-bottom: 0.682rem;',
- children: [
- Widget.Label({
- className: 'txt-title txt',
- label: getString('Session'),
- }),
- Widget.Label({
- justify: Gtk.Justification.CENTER,
- className: 'txt-small txt',
- label: getString('Use arrow keys to navigate.\nEnter to select, Esc to cancel.')
- }),
- ]
- });
- const SessionButtonRow = (children) => Widget.Box({
- hpack: 'center',
- className: 'spacing-h-15',
- children: children,
- });
- const sessionButtonRows = [
- SessionButtonRow([lockButton, logoutButton, sleepButton]),
- SessionButtonRow([hibernateButton, shutdownButton, rebootButton]),
- SessionButtonRow([cancelButton]),
- ]
- return Widget.Box({
- className: 'session-bg',
- css: `
- min-width: ${monitors[id].width}px;
- min-height: ${monitors[id].height}px;
- `, // idk why but height = screen height doesn't fill
- vertical: true,
- children: [
- Widget.EventBox({
- onPrimaryClick: () => closeWindowOnAllMonitors('session'),
- onSecondaryClick: () => closeWindowOnAllMonitors('session'),
- onMiddleClick: () => closeWindowOnAllMonitors('session'),
- }),
- Widget.Box({
- hpack: 'center',
- vexpand: true,
- vertical: true,
- children: [
- Widget.Box({
- vpack: 'center',
- vertical: true,
- className: 'spacing-v-15',
- children: [
- sessionDescription,
- ...sessionButtonRows,
- ]
- })
- ]
- })
- ],
- setup: (self) => self
- .hook(App, (_b, name, visible) => {
- if (visible) lockButton.grab_focus(); // Lock is the default option
- })
- ,
- });
-}
diff --git a/.config/ags/modules/sideleft/apis/ai_chatmessage.js b/.config/ags/modules/sideleft/apis/ai_chatmessage.js
deleted file mode 100644
index 4e7346e43..000000000
--- a/.config/ags/modules/sideleft/apis/ai_chatmessage.js
+++ /dev/null
@@ -1,491 +0,0 @@
-const { GLib, Gtk } = imports.gi;
-import GtkSource from "gi://GtkSource?version=3.0";
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { Box, Button, Label, Icon, Revealer, Scrollable, Stack } = Widget;
-const { execAsync, exec } = Utils;
-import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
-import md2pango, { replaceInlineLatexWithCodeBlocks } from '../../.miscutils/md2pango.js';
-import { darkMode } from "../../.miscutils/system.js";
-import { setupCursorHover } from "../../.widgetutils/cursorhover.js";
-
-const LATEX_DIR = `${GLib.get_user_cache_dir()}/ags/media/latex`;
-const USERNAME = GLib.get_user_name();
-
-function substituteLang(str) {
- const subs = [
- { from: 'javascript', to: 'js' },
- { from: 'bash', to: 'sh' },
- ];
- for (const { from, to } of subs) {
- if (from === str) return to;
- }
- return str;
-}
-
-const HighlightedCode = (content, lang) => {
- const buffer = new GtkSource.Buffer();
- const sourceView = new GtkSource.View({
- buffer: buffer,
- wrap_mode: Gtk.WrapMode.NONE,
- insertSpacesInsteadOfTabs: true,
- indentWidth: 4,
- tabWidth: 4,
- smartHomeEnd: true,
- smartBackspace: true,
- });
- const langManager = GtkSource.LanguageManager.get_default();
- let displayLang = langManager.get_language(substituteLang(lang)); // Set your preferred language
- if (displayLang) {
- buffer.set_language(displayLang);
- }
- const schemeManager = GtkSource.StyleSchemeManager.get_default();
- buffer.set_style_scheme(schemeManager.get_scheme(`custom${darkMode.value ? '' : '-light'}`));
- buffer.set_text(content, -1);
- return sourceView;
-}
-
-const TextBlock = (content = '') => {
- const widget = Label({
- attribute: {
- 'text': content,
- 'updateText': (text) => {
- widget.attribute.text = text;
- widget.label = md2pango(widget.attribute.text)
- },
- 'appendText': (text) => {
- widget.attribute.text += text;
- widget.label = md2pango(widget.attribute.text)
- },
- },
- hpack: 'fill',
- className: 'txt sidebar-chat-txtblock sidebar-chat-txt',
- useMarkup: true,
- xalign: 0,
- wrap: true,
- selectable: true,
- label: content,
- });
- return widget;
-}
-
-const ThinkBlock = (content = '', revealChild = true) => {
- const revealThought = Variable(revealChild);
- const mainText = Label({
- hpack: 'fill',
- className: `txt sidebar-chat-txtblock-think sidebar-chat-txt`,
- useMarkup: true,
- xalign: 0,
- wrap: true,
- selectable: true,
- label: content,
- });
- const mainTextRevealer = Revealer({
- transition: 'slide_down',
- revealChild: revealThought.value,
- child: mainText,
- setup: (self) => self.hook(revealThought, (self) => {
- self.revealChild = revealThought.value;
- })
- })
- const expandIcon = MaterialIcon(revealThought.value ? 'expand_less' : 'expand_more', 'norm', {
- setup: (self) => self.hook(revealThought, (self) => {
- self.label = revealThought.value ? 'expand_less' : 'expand_more';
- })
- });
- const widget = Box({
- attribute: {
- 'text': content,
- 'updateText': (text) => {
- widget.attribute.text = text;
- mainText.label = md2pango(widget.attribute.text);
- },
- 'appendText': (text) => {
- widget.attribute.text += text;
- mainText.label = md2pango(widget.attribute.text);
- },
- 'done': () => {
- revealThought.value = false;
- }
- },
- className: 'sidebar-chat-thinkblock',
- vertical: true,
- children: [
- Button({
- onClicked: (self) => {
- revealThought.value = !revealThought.value;
- },
- child: Box({
- className: 'spacing-h-10 padding-10',
- children: [
- Box({
- homogeneous: true,
- valign: 'center',
- className: 'sidebar-chat-thinkblock-icon',
- children: [MaterialIcon('neurology', 'large')]
- }),
- Label({
- valign: 'center',
- hexpand: true,
- xalign: 0,
- label: 'Chain of Thought',
- className: 'txt sidebar-chat-thinkblock-txt',
- }),
- Box({
- className: 'sidebar-chat-thinkblock-btn-arrow',
- homogeneous: true,
- children: [expandIcon],
- }),
- ]
- }),
- setup: setupCursorHover,
- }),
- mainTextRevealer,
- ]
- });
- return widget;
-}
-
-Utils.execAsync(['bash', '-c', `rm -rf ${LATEX_DIR}`])
- .then(() => Utils.execAsync(['bash', '-c', `mkdir -p ${LATEX_DIR}`]))
- .catch(print);
-const LatexBlock = (content = '') => {
- const latexViewArea = Box({
- // vscroll: 'never',
- // hscroll: 'automatic',
- // homogeneous: true,
- attribute: {
- 'render': async (self, text) => {
- if (text.length == 0) return;
- const styleContext = self.get_style_context();
- const fontSize = styleContext.get_property('font-size', Gtk.StateFlags.NORMAL);
-
- const timeSinceEpoch = Date.now();
- const fileName = `${timeSinceEpoch}.tex`;
- const outFileName = `${timeSinceEpoch}-symbolic.svg`;
- const outIconName = `${timeSinceEpoch}-symbolic`;
- const scriptFileName = `${timeSinceEpoch}-render.sh`;
- const filePath = `${LATEX_DIR}/${fileName}`;
- const outFilePath = `${LATEX_DIR}/${outFileName}`;
- const scriptFilePath = `${LATEX_DIR}/${scriptFileName}`;
-
- Utils.writeFile(text, filePath).catch(print);
- // Since MicroTex doesn't support file path input properly, we gotta cat it
- // And escaping such a command is a fucking pain so I decided to just generate a script
- // Note: MicroTex doesn't support `&=`
- // You can add this line in the middle for debugging: echo "$text" > ${filePath}.tmp
- const renderScript = `#!/usr/bin/env bash
-text=$(cat ${filePath} | sed 's/$/ \\\\\\\\/g' | sed 's/&=/=/g')
-cd /opt/MicroTeX
-./LaTeX -headless -input="$text" -output=${outFilePath} -textsize=${fontSize * 1.1} -padding=0 -maxwidth=${latexViewArea.get_allocated_width() * 0.85} > /dev/null 2>&1
-sed -i 's/fill="rgb(0%, 0%, 0%)"/style="fill:#000000"/g' ${outFilePath}
-sed -i 's/stroke="rgb(0%, 0%, 0%)"/stroke="${darkMode.value ? '#ffffff' : '#000000'}"/g' ${outFilePath}
-`;
- Utils.writeFile(renderScript, scriptFilePath).catch(print);
- Utils.exec(`chmod a+x ${scriptFilePath}`)
- Utils.timeout(100, () => {
- Utils.exec(`bash ${scriptFilePath}`);
- Gtk.IconTheme.get_default().append_search_path(LATEX_DIR);
-
- self.child?.destroy();
- self.child = Gtk.Image.new_from_icon_name(outIconName, 0);
- })
- }
- },
- setup: (self) => self.attribute.render(self, content).catch(print),
- });
- const wholeThing = Box({
- className: 'sidebar-chat-latex',
- homogeneous: true,
- attribute: {
- 'text': content,
- 'updateText': (text) => {
- wholeThing.attribute.text = text;
- latexViewArea.attribute.render(latexViewArea, wholeThing.attribute.text).catch(print);
- },
- 'appendText': (text) => {
- wholeThing.attribute.text += text;
- latexViewArea.attribute.render(latexViewArea, wholeThing.attribute.text).catch(print);
- },
- },
- children: [Scrollable({
- vscroll: 'never',
- hscroll: 'automatic',
- child: latexViewArea
- })]
- })
- return wholeThing;
-}
-
-const CodeBlock = (content = '', lang = 'txt') => {
- if (lang == 'tex' || lang == 'latex') {
- return LatexBlock(content);
- }
- const topBar = Box({
- className: 'sidebar-chat-codeblock-topbar',
- children: [
- Label({
- label: lang,
- className: 'sidebar-chat-codeblock-topbar-txt',
- }),
- Box({
- hexpand: true,
- }),
- Button({
- className: 'sidebar-chat-codeblock-topbar-btn',
- child: Box({
- className: 'spacing-h-5',
- children: [
- MaterialIcon('content_copy', 'small'),
- Label({
- label: 'Copy',
- })
- ]
- }),
- onClicked: (self) => {
- const buffer = sourceView.get_buffer();
- const copyContent = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), false); // TODO: fix this
- execAsync([`wl-copy`, `${copyContent}`]).catch(print);
- },
- }),
- ]
- })
- // Source view
- const sourceView = HighlightedCode(content, lang);
-
- const codeBlock = Box({
- attribute: {
- 'updateText': (text) => {
- // Enable useful features for multi-line code
- if (text.split('\n').length > 1) {
- sourceView.autoIndent = true;
- sourceView.highlightCurrentLine = true;
- sourceView.showLineNumbers = true;
- sourceView.showLineMarks = true;
- }
- sourceView.get_buffer().set_text(text, -1);
- },
- 'appendText': (text) => {
- codeBlock.attribute.updateText(sourceView.get_buffer().text + text);
- },
- },
- className: 'sidebar-chat-codeblock',
- vertical: true,
- children: [
- topBar,
- Box({
- className: 'sidebar-chat-codeblock-code',
- homogeneous: true,
- children: [Scrollable({
- vscroll: 'never',
- hscroll: 'automatic',
- child: sourceView,
- })],
- })
- ],
- setup: (self) => self.hook(darkMode, (self) => {
- const schemeManager = GtkSource.StyleSchemeManager.get_default();
- Utils.timeout(1000, () => { // Wait for the theme to be loaded
- sourceView.buffer.set_style_scheme(schemeManager.get_scheme(`custom${darkMode.value ? '' : '-light'}`));
- });
- }, "changed"),
- })
-
- // const schemeIds = styleManager.get_scheme_ids();
-
- // print("Available Style Schemes:");
- // for (let i = 0; i < schemeIds.length; i++) {
- // print(schemeIds[i]);
- // }
- return codeBlock;
-}
-
-const Divider = () => Box({
- className: 'sidebar-chat-divider',
-})
-
-const MessageContent = (content) => {
- const contentBox = Box({
- vertical: true,
- attribute: {
- 'lastUpdateTextLength': 0,
- 'inCode': false,
- 'fullUpdate': (self, content, useCursor = false) => {
- // First text widget
- if (contentBox.attribute.lastUpdateTextLength === 0
- && contentBox.get_children().length === 0
- ) {
- contentBox.add(TextBlock())
- }
-
- const codeBlockRegex = /^\s*```([a-zA-Z0-9]+)?\n?/;
- const thinkBlockStartRegex = /^\s*/; // Start:
- const thinkBlockEndRegex = /<\/think>\s*$/; // End:
- const dividerRegex = /^\s*---/;
- const newContent = content.slice(contentBox.attribute.lastUpdateTextLength);
- // print("CONTENT:'" + content + "'")
- // print("LAST UPDATE LENGTH:" + contentBox.attribute.lastUpdateTextLength)
- // print("NEW CONTENT:" + newContent)
- if (newContent.length == 0) return;
- let lines = replaceInlineLatexWithCodeBlocks(newContent).split('\n');
- // let lines = newContent.split('\n');
-
- // Process each line except the last line (potentially incomplete)
- let lastProcessed = 0;
- for (let [index, line] of lines.entries()) {
- if (index == lines.length - 1) break;
- // Code blocks
- if (codeBlockRegex.test(line)) {
- const kids = self.get_children();
- const lastLabel = kids[kids.length - 1];
- const blockContent = lines.slice(lastProcessed, index).join('\n');
-
- if (!contentBox.attribute.inCode) {
- lastLabel.attribute.appendText(blockContent);
- if (lastLabel.label === '') lastLabel.destroy();
- contentBox.add(CodeBlock('', codeBlockRegex.exec(line)[1]));
- }
- else {
- lastLabel.attribute.appendText(blockContent);
- contentBox.add(TextBlock());
- }
-
- lastProcessed = index + 1;
- contentBox.attribute.inCode = !contentBox.attribute.inCode;
- }
- // Think block
- if (!contentBox.attribute.inCode && (thinkBlockStartRegex.test(line) || thinkBlockEndRegex.test(line))) {
- const kids = self.get_children();
- const lastLabel = kids[kids.length - 1];
- const blockContent = lines.slice(lastProcessed, index).join('\n');
-
- lastLabel.attribute.appendText(blockContent);
- if (lastLabel.label === '') lastLabel.destroy();
- if (thinkBlockStartRegex.test(line)) contentBox.add(ThinkBlock());
- else {
- lastLabel.attribute.done();
- contentBox.add(TextBlock());
- }
-
- lastProcessed = index + 1;
- }
- // Breaks
- if (!contentBox.attribute.inCode && dividerRegex.test(line)) {
- const kids = self.get_children();
- const lastLabel = kids[kids.length - 1];
- const blockContent = lines.slice(lastProcessed, index).join('\n');
- lastLabel.attribute.appendText(blockContent);
- contentBox.add(Divider());
- contentBox.add(TextBlock());
- lastProcessed = index + 1;
- }
- }
- if (lastProcessed < lines.length - 1) {
- const kids = self.get_children();
- const lastLabel = kids[kids.length - 1];
- let blockContent = lines.slice(lastProcessed, lines.length - 1).join('\n') + '\n';
- lastLabel.attribute.appendText(blockContent);
- }
- // Debug: plain text
- // contentBox.add(Label({
- // hpack: 'fill',
- // className: 'txt sidebar-chat-txtblock sidebar-chat-txt',
- // useMarkup: false,
- // xalign: 0,
- // wrap: true,
- // selectable: true,
- // label: '------------------------------\n' + md2pango(content),
- // }))
- contentBox.show_all();
- contentBox.attribute.lastUpdateTextLength = content.length - lines[lines.length - 1].length;
- }
- }
- });
- contentBox.attribute.fullUpdate(contentBox, content, false);
- return contentBox;
-}
-
-export const ChatMessage = (message, modelName = 'Model') => {
- const TextSkeleton = (extraClassName = '') => Box({
- className: `sidebar-chat-message-skeletonline ${extraClassName}`,
- })
- const messageContentBox = MessageContent(message.content);
- const messageLoadingSkeleton = Box({
- vertical: true,
- className: 'spacing-v-5',
- children: Array.from({ length: 3 }, (_, id) => TextSkeleton(`sidebar-chat-message-skeletonline-offset${id}`)),
- })
- const messageArea = Stack({
- homogeneous: message.role !== 'user',
- transition: 'crossfade',
- transitionDuration: userOptions.animations.durationLarge,
- children: {
- 'thinking': messageLoadingSkeleton,
- 'message': messageContentBox,
- },
- shown: message.thinking ? 'thinking' : 'message',
- });
- const thisMessage = Box({
- className: 'sidebar-chat-message',
- homogeneous: true,
- children: [
- Box({
- vertical: true,
- children: [
- Label({
- hpack: 'start',
- xalign: 0,
- className: `txt txt-bold sidebar-chat-name sidebar-chat-name-${message.role == 'user' ? 'user' : 'bot'}`,
- wrap: true,
- useMarkup: true,
- label: (message.role === 'user' ? USERNAME : modelName),
- }),
- Box({
- homogeneous: true,
- className: 'sidebar-chat-messagearea',
- children: [messageArea]
- })
- ],
- setup: (self) => self
- .hook(message, (self, isThinking) => {
- messageArea.shown = message.thinking ? 'thinking' : 'message';
- }, 'notify::thinking')
- .hook(message, (self) => { // Message update
- messageContentBox.attribute.fullUpdate(messageContentBox, message.content, message.role != 'user');
- }, 'notify::content')
- .hook(message, (label, isDone) => { // Remove the cursor
- if (!isDone && message.role !== 'user') return;
- messageContentBox.attribute.fullUpdate(messageContentBox, message.content + '\n', false);
- // print('----------------')
- // print(message.content)
- }, 'notify::done')
- ,
- })
- ]
- });
- return thisMessage;
-}
-
-export const SystemMessage = (content, commandName, scrolledWindow) => {
- const messageContentBox = MessageContent(content + '\n'); // Add newline so everything is added
- const thisMessage = Box({
- className: 'sidebar-chat-message',
- children: [
- Box({
- vertical: true,
- children: [
- Label({
- xalign: 0,
- hpack: 'start',
- className: 'txt txt-bold sidebar-chat-name sidebar-chat-name-system',
- wrap: true,
- label: `System • ${commandName}`,
- }),
- messageContentBox,
- ],
- })
- ],
- });
- return thisMessage;
-}
diff --git a/.config/ags/modules/sideleft/apis/booru.js b/.config/ags/modules/sideleft/apis/booru.js
deleted file mode 100644
index b69d8beee..000000000
--- a/.config/ags/modules/sideleft/apis/booru.js
+++ /dev/null
@@ -1,546 +0,0 @@
-const { Gdk, GdkPixbuf, Gio, GLib, Gtk } = imports.gi;
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { Box, Button, EventBox, Label, Overlay, Revealer, Scrollable, Stack } = Widget;
-const { execAsync, exec } = Utils;
-import { fileExists } from '../../.miscutils/files.js';
-import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
-import { MarginRevealer } from '../../.widgethacks/advancedrevealers.js';
-import { setupCursorHover, setupCursorHoverInfo } from '../../.widgetutils/cursorhover.js';
-import BooruService from '../../../services/booru.js';
-import { SystemMessage } from './ai_chatmessage.js';
-import { AgsToggle } from '../../.commonwidgets/configwidgets_apps.js';
-
-const IMAGE_REVEAL_DELAY = 13; // Some wait for inits n other weird stuff
-const USER_CACHE_DIR = GLib.get_user_cache_dir();
-
-// Create cache folder and clear pics from previous session
-Utils.exec(`bash -c 'mkdir -p ${USER_CACHE_DIR}/ags/media/waifus'`);
-Utils.exec(`bash -c 'rm ${USER_CACHE_DIR}/ags/media/waifus/*'`);
-
-function getDomainName(url) {
- try {
- const match = url.match(/^(?:https?:\/\/)?(?:www\.)?([^\/]+)/i);
- if (!match) return null;
-
- const domainParts = match[1].split('.');
- if (domainParts.length > 2) {
- // Return only the last two parts (e.g., "yande.re" from "files.yande.re")
- return domainParts.slice(-2).join('.');
- }
- return match[1]; // Return as is if no subdomain
- } catch (error) {
- print(`Invalid URL: ${url}`);
- return null;
- }
-}
-
-const TagButton = (command, entry) => Button({
- className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small',
- // Interactions disabled for now because they aren't working
- // onClicked: () => { entry.buffer.text += `${command} ` },
- // setup: setupCursorHover,
- label: command,
-});
-
-const CommandButton = (command, displayName = command) => Button({
- className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small',
- onClicked: () => sendMessage(command),
- setup: setupCursorHover,
- label: displayName,
-});
-
-export const booruTabIcon = Box({
- hpack: 'center',
- homogeneous: true,
- children: [
- MaterialIcon('gallery_thumbnail', 'norm'),
- ]
-});
-
-const BooruInfo = () => {
- const booruLogo = Label({
- hpack: 'center',
- className: 'sidebar-chat-welcome-logo',
- label: 'gallery_thumbnail',
- })
- return Box({
- vertical: true,
- vexpand: true,
- className: 'spacing-v-15',
- children: [
- booruLogo,
- Label({
- className: 'txt txt-title-small sidebar-chat-welcome-txt',
- wrap: true,
- justify: Gtk.Justification.CENTER,
- label: 'Anime booru',
- }),
- Box({
- className: 'spacing-h-5',
- hpack: 'center',
- children: [
- Label({
- className: 'txt-smallie txt-subtext',
- wrap: true,
- justify: Gtk.Justification.CENTER,
- label: getString('Powered by yande.re and konachan'),
- }),
- Button({
- className: 'txt-subtext txt-norm icon-material',
- label: 'info',
- tooltipText: getString('An image booru. May contain NSFW content.\nWatch your back.\n\nDisclaimer: Not affiliated with the provider\nnor responsible for any of its content.'),
- setup: setupCursorHoverInfo,
- }),
- ]
- }),
- ]
- });
-}
-
-export const BooruSettings = () => MarginRevealer({
- transition: 'slide_down',
- revealChild: true,
- child: Box({
- vertical: true,
- className: 'sidebar-chat-settings',
- children: [
- Box({
- vertical: true,
- hpack: 'center',
- className: 'sidebar-chat-settings-toggles',
- children: [
- AgsToggle({
- icon: 'menstrual_health',
- name: getString('Lewds'),
- desc: getString("Shows naughty stuff when enabled"),
- option: 'sidebar.image.allowNsfw',
- extraOnChange: (self, newValue) => {
- BooruService.nsfw = newValue;
- },
- extraSetup: (self) => self.hook(BooruService, (self) => {
- self.attribute.enabled.value = BooruService.nsfw;
- }, 'notify::nsfw')
- }),
- ]
- })
- ]
- })
-});
-
-const booruWelcome = Box({
- vexpand: true,
- homogeneous: true,
- child: Box({
- className: 'spacing-v-15 margin-top-15 margin-bottom-15',
- vpack: 'center',
- vertical: true,
- children: [
- BooruInfo(),
- BooruSettings(),
- ]
- })
-});
-
-const BooruPage = (taglist, serviceName = 'Booru') => {
- const PageState = (icon, name) => Box({
- className: 'spacing-h-5 txt margin-right-5',
- children: [
- Label({
- className: 'sidebar-waifu-txt txt-smallie',
- xalign: 0,
- label: name,
- }),
- MaterialIcon(icon, 'norm'),
- ]
- })
- const ImageAction = ({ name, icon, action }) => Button({
- className: 'sidebar-waifu-image-action txt-norm icon-material',
- tooltipText: name,
- label: icon,
- onClicked: action,
- setup: setupCursorHover,
- })
- const PreviewImage = (data, delay = 0) => {
- const imageArea = Widget.DrawingArea({
- className: 'sidebar-booru-image-drawingarea',
- });
- const imageBox = Box({
- className: 'sidebar-booru-image',
- // css: `background-image: url('${data.preview_url}');`,
- attribute: {
- 'update': (self, data, force = false) => {
- const imagePath = `${USER_CACHE_DIR}/ags/media/waifus/${data.md5}.${data.file_ext}`;
- // const widgetStyleContext = imageArea.get_style_context();
- // const widgetWidth = widgetStyleContext.get_property('min-width', Gtk.StateFlags.NORMAL);
- // const widgetWidth = Math.min(Math.floor(booruContent.get_allocated_width() * 0.9 / userOptions.sidebar.image.columns), data["preview_width"]);
- const widgetWidth = Math.floor(booruContent.get_allocated_width() * 0.9 / userOptions.sidebar.image.columns);
- const widgetHeight = widgetWidth / data.aspect_ratio;
- imageArea.set_size_request(widgetWidth, widgetHeight);
- const showImage = () => {
- const pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(imagePath, widgetWidth, widgetHeight, false);
- imageArea.connect("draw", (widget, cr) => {
- const borderRadius = widget.get_style_context().get_property('border-radius', Gtk.StateFlags.NORMAL);
-
- // Draw a rounded rectangle
- cr.arc(borderRadius, borderRadius, borderRadius, Math.PI, 1.5 * Math.PI);
- cr.arc(widgetWidth - borderRadius, borderRadius, borderRadius, 1.5 * Math.PI, 2 * Math.PI);
- cr.arc(widgetWidth - borderRadius, widgetHeight - borderRadius, borderRadius, 0, 0.5 * Math.PI);
- cr.arc(borderRadius, widgetHeight - borderRadius, borderRadius, 0.5 * Math.PI, Math.PI);
- cr.closePath();
- cr.clip();
-
- // Paint image as bg
- Gdk.cairo_set_source_pixbuf(cr, pixbuf, (widgetWidth - widgetWidth) / 2, (widgetHeight - widgetHeight) / 2);
- cr.paint();
- });
- self.queue_draw();
- imageRevealer.revealChild = true;
- }
- // Show
- // const downloadCommand = `wget -O '${imagePath}' '${data.preview_url}'`;
- const downloadCommand = `curl -L -o '${imagePath}' '${data.preview_url}'`;
- if (!force && fileExists(imagePath)) showImage();
- else Utils.timeout(delay, () => Utils.execAsync(['bash', '-c', downloadCommand])
- .then(showImage)
- .catch(print)
- );
- },
- },
- child: imageArea,
- setup: (self) => {
- Utils.timeout(1000, () => self.attribute.update(self, data));
- }
- });
- const imageActions = Revealer({
- transition: 'crossfade',
- transitionDuration: userOptions.animations.durationLarge,
- child: Box({
- vpack: 'start',
- className: 'sidebar-booru-image-actions spacing-h-3',
- children: [
- Box({ hexpand: true }),
- ImageAction({
- name: `${getString('Go to file url')} (${getDomainName(data.file_url)})`,
- icon: 'file_open',
- action: () => execAsync(['xdg-open', `https://${getDomainName(data.file_url)}/post/show/${data.id}`]).catch(print),
- }),
- ImageAction({
- name: `${getString('Go to source')} (${getDomainName(data.source)})`,
- icon: 'open_in_new',
- action: () => execAsync(['xdg-open', `${data.source}`]).catch(print),
- }),
- ImageAction({
- name: getString('Save image'),
- icon: 'save',
- action: (self) => {
- const currentTags = BooruService.queries.at(-1).realTagList.filter(tag => !tag.includes('rating:'));
- const tagDirectory = currentTags.join('+');
- const fileName = decodeURIComponent((data.file_url).substring((data.file_url).lastIndexOf('/') + 1));
- const saveCommand = `mkdir -p "$(xdg-user-dir PICTURES)/homework/${data.is_nsfw ? '🌶️/' : ''}" && curl -L -o "$(xdg-user-dir PICTURES)/homework/${data.is_nsfw ? '🌶️/' : ''}${fileName}" '${data.file_url}'`;
- print(saveCommand)
- execAsync(['bash', '-c', saveCommand])
- .then(() => self.label = 'done')
- .catch(print);
- },
- }),
- ImageAction({
- name: getString('Set as wallpaper'),
- icon: 'wallpaper',
- action: (self) => {
- const currentTags = BooruService.queries.at(-1).realTagList.filter(tag => !tag.includes('rating:'));
- let fileExtension = data.file_ext || 'jpg';
- print(data)
- const fileName = decodeURIComponent((data.file_url).substring((data.file_url).lastIndexOf('/') + 1));
- const saveCommand = `mkdir -p "$(xdg-user-dir PICTURES)/Wallpapers" && curl -L -o "$(xdg-user-dir PICTURES)/Wallpapers/${fileName}" '${data.file_url}'`;
- const setWallpaperCommand = `${App.configDir}/scripts/color_generation/switchwall.sh "$(xdg-user-dir PICTURES)/Wallpapers/${fileName}"`;
- // const
- execAsync(['bash', '-c', `${saveCommand} && ${setWallpaperCommand}`])
- .then(() => self.label = 'done')
- .catch(print);
- },
- }),
- ]
- })
- });
- const imageOverlay = Overlay({
- passThrough: true,
- child: imageBox,
- overlays: [imageActions]
- });
- const imageRevealer = Revealer({
- transition: 'slide_down',
- transitionDuration: userOptions.animations.durationLarge,
- child: EventBox({
- onHover: () => { imageActions.revealChild = true },
- onHoverLost: () => { imageActions.revealChild = false },
- child: imageOverlay,
- })
- })
- return imageRevealer;
- }
- const downloadState = Stack({
- homogeneous: false,
- transition: 'slide_up_down',
- transitionDuration: userOptions.animations.durationSmall,
- children: {
- 'api': PageState('api', getString('Calling API')),
- 'download': PageState('downloading', getString('Downloading image')),
- 'done': PageState('done', getString('Finished!')),
- 'error': PageState('error', getString('Error')),
- },
- });
- const downloadIndicator = MarginRevealer({
- vpack: 'center',
- transition: 'slide_left',
- revealChild: true,
- child: downloadState,
- });
- const pageHeading = Box({
- vertical: true,
- children: [
- Box({
- children: [
- Label({
- hpack: 'start',
- className: `sidebar-booru-provider`,
- label: `${serviceName}`,
- truncate: 'end',
- maxWidthChars: 20,
- }),
- Box({ hexpand: true }),
- downloadIndicator,
- ]
- }),
- Box({
- className: 'margin-5',
- children: [
- Scrollable({
- hexpand: true,
- vscroll: 'never',
- hscroll: 'automatic',
- child: Box({
- hpack: 'fill',
- className: 'spacing-h-5',
- children: [
- ...taglist.map((tag) => TagButton(tag)),
- Box({ hexpand: true }),
- ]
- })
- }),
- ]
- })
- ]
- });
- const pageImages = Box({
- hpack: 'start',
- homogeneous: true,
- className: 'sidebar-booru-imagegrid',
- })
- const pageTip = Revealer({
- transition: 'slide_down',
- transitionDuration: 0,
- revealChild: false,
- child: Box({
- className: 'txt-subtext margin-5',
- children: [
- Box({
- homogeneous: true,
- className: 'sidebar-booru-tip-icon',
- children: [MaterialIcon('lightbulb', 'larger')]
- }),
- Label({
- label: getString("No tag in mind? Type a page number"),
- className: 'txt-smallie',
- wrap: true,
- xalign: 0,
- })
- ]
- })
- })
- const pageContentRevealer = Revealer({
- transition: 'slide_down',
- transitionDuration: userOptions.animations.durationLarge,
- revealChild: false,
- child: Box({
- vertical: true,
- children: [
- pageImages,
- pageTip,
- ]
- }),
- });
- const thisPage = Box({
- homogeneous: true,
- className: 'sidebar-chat-message',
- attribute: {
- 'imagePath': '',
- 'isNsfw': false,
- 'showContent': () => {
- Utils.timeout(IMAGE_REVEAL_DELAY,
- () => pageContentRevealer.revealChild = true
- );
- },
- 'update': (data, force = false) => {
- // Sort by .aspect_ratio
- data = data.sort(
- (a, b) => a.aspect_ratio - b.aspect_ratio
- );
- if (data.length == 0) {
- pageTip.revealChild = true;
- downloadState.shown = 'error';
- thisPage.attribute.showContent();
- return;
- }
- const imageColumns = userOptions.sidebar.image.columns;
- const imageRows = data.length / imageColumns;
-
- // Init cols
- pageImages.children = Array.from(
- { length: imageColumns },
- (_, i) => Box({
- attribute: { height: 0 },
- vertical: true,
- })
- );
- // Greedy add O(n^2) 😭
- for (let i = 0; i < data.length; i++) {
- // Find column with lowest length
- let minHeight = Infinity;
- let minIndex = -1;
- for (let j = 0; j < imageColumns; j++) {
- const height = pageImages.children[j].attribute.height;
- if (height < minHeight) {
- minHeight = height;
- minIndex = j;
- }
- }
- // Add image to it
- pageImages.children[minIndex].pack_start(PreviewImage(data[i], minIndex), false, false, 0)
- pageImages.children[minIndex].attribute.height += 1 / data[i].aspect_ratio; // we want height/width
- }
- pageImages.show_all();
-
- // Reveal stuff
- thisPage.attribute.showContent();
- downloadIndicator.attribute.hide();
- },
- },
- children: [Box({
- vertical: true,
- children: [
- pageHeading,
- Box({
- vertical: true,
- children: [pageContentRevealer],
- })
- ]
- })],
- });
- return thisPage;
-}
-
-const booruContent = Box({
- className: 'spacing-v-15',
- vertical: true,
- attribute: {
- 'map': new Map(),
- },
- setup: (self) => self
- .hook(BooruService, (box, id) => {
- if (id === undefined) return;
- const newPage = BooruPage(BooruService.queries[id].taglist, BooruService.queries[id].providerName);
- box.add(newPage);
- box.show_all();
- box.attribute.map.set(id, newPage);
- }, 'newResponse')
- .hook(BooruService, (box, id) => {
- if (id === undefined) return;
- if (!BooruService.responses[id]) return;
- box.attribute.map.get(id)?.attribute.update(BooruService.responses[id]);
- }, 'updateResponse')
- ,
-});
-
-export const BooruView = (chatEntry) => Scrollable({
- className: 'sidebar-chat-viewport',
- vexpand: true,
- child: Box({
- vertical: true,
- children: [
- booruWelcome,
- booruContent,
- ]
- }),
- setup: (scrolledWindow) => {
- // Show scrollbar
- scrolledWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
- const vScrollbar = scrolledWindow.get_vscrollbar();
- vScrollbar.get_style_context().add_class('sidebar-scrollbar');
- // Avoid click-to-scroll-widget-to-view behavior
- Utils.timeout(1, () => {
- const viewport = scrolledWindow.child;
- viewport.set_focus_vadjustment(new Gtk.Adjustment(undefined));
- })
- // Scroll to bottom with new content if chat entry not focused
- const adjustment = scrolledWindow.get_vadjustment();
- adjustment.connect("changed", () => {
- if (!chatEntry.hasFocus) return;
- adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size());
- })
- }
-});
-
-export const booruCommands = Box({
- className: 'spacing-h-5',
- setup: (self) => {
- self.pack_end(CommandButton('/clear'), false, false, 0);
- self.pack_end(CommandButton('+'), false, false, 0);
- self.pack_end(CommandButton('/mode konachan', 'Konachan'), false, false, 0);
- self.pack_end(CommandButton('/mode yandere', 'yande.re'), false, false, 0);
- }
-});
-
-const clearChat = () => { // destroy!!
- booruContent.attribute.map.forEach((value, key, map) => {
- value.destroy();
- value = null;
- });
-}
-
-export const sendMessage = (text, booruView) => {
- // Commands
- if (text.startsWith('+')) { // Next page
- const lastQuery = BooruService.queries.at(-1);
- BooruService.fetch(`${lastQuery.realTagList.join(' ')} ${lastQuery.page + 1}`)
- }
- else if (text.startsWith('/')) {
- if (text.startsWith('/clear')) clearChat();
- else if (text.startsWith('/safe')) {
- BooruService.nsfw = false;
- const message = SystemMessage(`Switched to safe mode`, '/safe', booruView)
- booruContent.add(message);
- booruContent.show_all();
- booruContent.attribute.map.set(Date.now(), message);
- }
- else if (text.startsWith('/lewd')) {
- BooruService.nsfw = true;
- const message = SystemMessage(`Tiddies enabled`, '/lewd', booruView)
- booruContent.add(message);
- booruContent.show_all();
- booruContent.attribute.map.set(Date.now(), message);
- }
- else if (text.startsWith('/mode')) {
- const mode = text.slice(text.indexOf(' ') + 1);
- BooruService.mode = mode;
- const message = SystemMessage(`Changed provider to ${BooruService.providerName}`, '/mode', booruView)
- booruContent.add(message);
- booruContent.show_all();
- booruContent.attribute.map.set(Date.now(), message);
- }
- else if (text.startsWith('/next')) {
- sendMessage('+')
- }
- }
- else BooruService.fetch(text);
-}
\ No newline at end of file
diff --git a/.config/ags/modules/sideleft/apis/chatgpt.js b/.config/ags/modules/sideleft/apis/chatgpt.js
deleted file mode 100644
index 06127f551..000000000
--- a/.config/ags/modules/sideleft/apis/chatgpt.js
+++ /dev/null
@@ -1,377 +0,0 @@
-const { Gtk } = imports.gi;
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-
-const { Box, Button, Icon, Label, Revealer, Scrollable } = Widget;
-import GPTService from '../../../services/gpt.js';
-import { setupCursorHover, setupCursorHoverInfo } from '../../.widgetutils/cursorhover.js';
-import { SystemMessage, ChatMessage } from "./ai_chatmessage.js";
-import { ConfigToggle, ConfigSegmentedSelection, ConfigGap } from '../../.commonwidgets/configwidgets.js';
-import { markdownTest } from '../../.miscutils/md2pango.js';
-import { MarginRevealer } from '../../.widgethacks/advancedrevealers.js';
-import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
-
-const AGS_CONFIG_FILE = `${App.configDir}/user_options.jsonc`;
-
-export const chatGPTTabIcon = Icon({
- hpack: 'center',
- icon: `openai-symbolic`,
-});
-
-const ProviderSwitcher = () => {
- const ProviderChoice = (id, provider) => {
- const providerSelected = MaterialIcon('check', 'norm', {
- setup: (self) => self.hook(GPTService, (self) => {
- self.toggleClassName('invisible', GPTService.providerID !== id);
- }, 'providerChanged')
- });
- return Button({
- tooltipText: provider.description,
- onClicked: () => {
- GPTService.providerID = id;
- providerList.revealChild = false;
- indicatorChevron.label = 'expand_more';
- // Save provider to config
- Utils.execAsync(['bash', '-c', `${App.configDir}/scripts/ags/agsconfigurator.py \
- --key ai.defaultGPTProvider \
- --value ${id} \
- --file ${AGS_CONFIG_FILE}`
- ]).catch(print);
- },
- child: Box({
- className: 'spacing-h-10 txt',
- children: [
- Icon({
- icon: provider['logo_name'],
- className: 'txt-large'
- }),
- Label({
- hexpand: true,
- xalign: 0,
- className: 'txt-small',
- label: provider.name,
- }),
- providerSelected
- ],
- }),
- setup: setupCursorHover,
- });
- }
- let indicatorIcon = Icon({
- icon: GPTService.providers[GPTService._currentProvider]['logo_name'],
- className: 'txt-large',
- setup: (self) => self.hook(GPTService, (self) => {
- self.icon = GPTService.providers[GPTService.providerID]['logo_name'];
- }, 'providerChanged')
- });
- const indicatorChevron = MaterialIcon('expand_more', 'norm');
- const indicatorButton = Button({
- tooltipText: getString('Select ChatGPT-compatible API provider'),
- child: Box({
- className: 'spacing-h-10 txt',
- children: [
- indicatorIcon,
- Label({
- hexpand: true,
- xalign: 0,
- className: 'txt-small',
- label: GPTService.providerID,
- setup: (self) => self.hook(GPTService, (self) => {
- self.label = `${GPTService.providers[GPTService.providerID]['name']}`;
- }, 'providerChanged')
- }),
- indicatorChevron,
- ]
- }),
- onClicked: () => {
- providerList.revealChild = !providerList.revealChild;
- indicatorChevron.label = (providerList.revealChild ? 'expand_less' : 'expand_more');
- },
- setup: setupCursorHover,
- });
- const providerList = Revealer({
- revealChild: false,
- transition: 'slide_down',
- transitionDuration: userOptions.animations.durationLarge,
- child: Box({
- vertical: true, className: 'spacing-v-5 sidebar-chat-providerswitcher-list',
- children: [
- Box({ className: 'separator-line margin-top-5 margin-bottom-5' }),
- Box({
- className: 'spacing-v-5',
- vertical: true,
- setup: (self) => self.hook(GPTService, (self) => {
- self.children = Object.entries(GPTService.providers)
- .map(([id, provider]) => ProviderChoice(id, provider));
- }, 'initialized'),
- })
- ]
- })
- })
- return Box({
- hpack: 'center',
- vertical: true,
- className: 'sidebar-chat-providerswitcher',
- children: [
- indicatorButton,
- providerList,
- ]
- })
-}
-
-const GPTInfo = () => {
- const openAiLogo = Icon({
- hpack: 'center',
- className: 'sidebar-chat-welcome-logo',
- icon: `openai-symbolic`,
- });
- return Box({
- vertical: true,
- className: 'spacing-v-15',
- children: [
- openAiLogo,
- Label({
- className: 'txt txt-title-small sidebar-chat-welcome-txt',
- wrap: true,
- justify: Gtk.Justification.CENTER,
- label: `Assistant (GPTs)`,
- }),
- Box({
- className: 'spacing-h-5',
- hpack: 'center',
- children: [
- Label({
- className: 'txt-smallie txt-subtext',
- wrap: true,
- justify: Gtk.Justification.CENTER,
- label: getString('Provider shown above'),
- }),
- Button({
- className: 'txt-subtext txt-norm icon-material',
- label: 'info',
- tooltipText: getString("Chat with models compatible with OpenAI's Chat Completions API.\nNot affiliated, endorsed, or sponsored by any of the providers."),
- setup: setupCursorHoverInfo,
- }),
- ]
- }),
- ]
- });
-}
-
-const GPTSettings = () => MarginRevealer({
- transition: 'slide_down',
- revealChild: true,
- extraSetup: (self) => self
- .hook(GPTService, (self) => Utils.timeout(200, () => {
- self.attribute.hide();
- }), 'newMsg')
- .hook(GPTService, (self) => Utils.timeout(200, () => {
- self.attribute.show();
- }), 'clear')
- ,
- child: Box({
- vertical: true,
- className: 'sidebar-chat-settings',
- children: [
- ConfigSegmentedSelection({
- hpack: 'center',
- icon: 'casino',
- name: 'Randomness',
- desc: getString('The model\'s temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1'),
- options: [
- { value: 0.00, name: getString('Precise'), },
- { value: 0.50, name: getString('Balanced'), },
- { value: 1.00, name: getString('Creative'), },
- ],
- initIndex: 1,
- onChange: (value, name) => {
- GPTService.temperature = value;
- },
- }),
- ConfigGap({ vertical: true, size: 10 }), // Note: size can only be 5, 10, or 15
- Box({
- vertical: true,
- hpack: 'center',
- className: 'sidebar-chat-settings-toggles',
- children: [
- ConfigToggle({
- icon: 'model_training',
- name: getString('Prompt'),
- desc: getString('Tells the model:\n- It\'s a Linux sidebar assistant\n- Be brief and use bullet points'),
- initValue: GPTService.assistantPrompt,
- onChange: (self, newValue) => {
- GPTService.assistantPrompt = newValue;
- },
- }),
- ]
- })
- ]
- })
-});
-
-export const OpenaiApiKeyInstructions = () => Box({
- homogeneous: true,
- children: [Revealer({
- transition: 'slide_down',
- transitionDuration: userOptions.animations.durationLarge,
- setup: (self) => self
- .hook(GPTService, (self, hasKey) => {
- self.revealChild = (
- GPTService.providers[GPTService.providerID]["requires_key"]
- && GPTService.key.length == 0);
- }, 'hasKey')
- ,
- child: Button({
- child: Label({
- useMarkup: true,
- wrap: true,
- className: 'txt sidebar-chat-welcome-txt',
- justify: Gtk.Justification.CENTER,
- label: getString('An API key is required\nYou can grab one here, then enter it below')
- }),
- setup: setupCursorHover,
- onClicked: () => {
- Utils.execAsync(['bash', '-c', `xdg-open ${GPTService.getKeyUrl}`]);
- }
- })
- })]
-});
-
-const GPTWelcome = () => Box({
- vexpand: true,
- homogeneous: true,
- child: Box({
- className: 'spacing-v-15 margin-top-15 margin-bottom-15',
- vpack: 'center',
- vertical: true,
- children: [
- GPTInfo(),
- OpenaiApiKeyInstructions(),
- GPTSettings(),
- ]
- })
-});
-
-export const chatContent = Box({
- className: 'spacing-v-5',
- vertical: true,
- setup: (self) => self
- .hook(GPTService, (box, id) => {
- const message = GPTService.messages[id];
- if (!message) return;
- box.add(ChatMessage(message, `Model (${GPTService.providers[GPTService.providerID]['name']})`))
- }, 'newMsg')
- .hook(GPTService, (self, hasKey) => {
- self.revealChild = (
- GPTService.providers[GPTService.providerID]["requires_key"]
- && GPTService.key.length == 0);
- }, 'providerChanged')
- ,
-});
-
-const clearChat = () => {
- GPTService.clear();
- const children = chatContent.get_children();
- for (let i = 0; i < children.length; i++) {
- const child = children[i];
- child.destroy();
- }
-}
-
-const CommandButton = (command) => Button({
- className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small',
- onClicked: () => sendMessage(command),
- setup: setupCursorHover,
- label: command,
-});
-
-export const chatGPTCommands = Box({
- className: 'spacing-h-5',
- children: [
- Box({ hexpand: true }),
- CommandButton('/key'),
- CommandButton('/model'),
- CommandButton('/clear'),
- ]
-});
-
-export const sendMessage = (text) => {
- // Check if text or API key is empty
- if (text.length == 0) return;
- if (GPTService.providers[GPTService.providerID]["requires_key"]
- && GPTService.key.length == 0
- && !text.startsWith('/key')) {
- GPTService.key = text;
- chatContent.add(SystemMessage(`Key saved to \`${GPTService.keyPath}\`\nUpdate anytime with \`/key YOUR_API_KEY\`.`, 'API Key', ChatGPTView));
- text = '';
- return;
- }
- // Commands
- if (text.startsWith('/')) {
- if (text.startsWith('/clear')) clearChat();
- else if (text.startsWith('/model')) chatContent.add(SystemMessage(`${getString("Currently using")} \`${GPTService.modelName}\``, '/model', ChatGPTView))
- else if (text.startsWith('/prompt')) {
- const firstSpaceIndex = text.indexOf(' ');
- const prompt = text.slice(firstSpaceIndex + 1);
- if (firstSpaceIndex == -1 || prompt.length < 1) {
- chatContent.add(SystemMessage(`Usage: \`/prompt MESSAGE\``, '/prompt', ChatGPTView))
- }
- else {
- GPTService.addMessage('user', prompt)
- }
- }
- else if (text.startsWith('/key')) {
- const parts = text.split(' ');
- if (parts.length == 1) chatContent.add(SystemMessage(
- `${getString("Key stored in:")}\n\`${GPTService.keyPath}\`\n${getString("To update this key, type")} \`/key YOUR_API_KEY\``,
- '/key',
- ChatGPTView));
- else {
- GPTService.key = parts[1];
- chatContent.add(SystemMessage(`${getString("Updated API Key at")}\n\`${GPTService.keyPath}\``, '/key', ChatGPTView));
- }
- }
- else if (text.startsWith('/test'))
- chatContent.add(SystemMessage(markdownTest, `Markdown test`, ChatGPTView));
- else
- chatContent.add(SystemMessage(getString("Invalid command."), 'Error', ChatGPTView))
- }
- else {
- GPTService.send(text);
- }
-}
-
-export const ChatGPTView = (chatEntry) => Box({
- vertical: true,
- children: [
- ProviderSwitcher(),
- Scrollable({
- className: 'sidebar-chat-viewport',
- vexpand: true,
- child: Box({
- vertical: true,
- children: [
- GPTWelcome(),
- chatContent,
- ]
- }),
- setup: (scrolledWindow) => {
- // Show scrollbar
- scrolledWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
- const vScrollbar = scrolledWindow.get_vscrollbar();
- vScrollbar.get_style_context().add_class('sidebar-scrollbar');
- // Avoid click-to-scroll-widget-to-view behavior
- Utils.timeout(1, () => {
- const viewport = scrolledWindow.child;
- viewport.set_focus_vadjustment(new Gtk.Adjustment(undefined));
- })
- // Always scroll to bottom with new content
- const adjustment = scrolledWindow.get_vadjustment();
- adjustment.connect("changed", () => {
- if (!chatEntry.hasFocus) return;
- adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size());
- })
- }
- })
- ]
-});
\ No newline at end of file
diff --git a/.config/ags/modules/sideleft/apis/gemini.js b/.config/ags/modules/sideleft/apis/gemini.js
deleted file mode 100644
index b31380662..000000000
--- a/.config/ags/modules/sideleft/apis/gemini.js
+++ /dev/null
@@ -1,296 +0,0 @@
-const { Gtk } = imports.gi;
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-
-const { Box, Button, Icon, Label, Revealer, Scrollable } = Widget;
-import GeminiService from '../../../services/gemini.js';
-import { setupCursorHover, setupCursorHoverInfo } from '../../.widgetutils/cursorhover.js';
-import { SystemMessage, ChatMessage } from "./ai_chatmessage.js";
-import { ConfigToggle, ConfigSegmentedSelection, ConfigGap } from '../../.commonwidgets/configwidgets.js';
-import { markdownTest } from '../../.miscutils/md2pango.js';
-import { MarginRevealer } from '../../.widgethacks/advancedrevealers.js';
-import { AgsToggle } from '../../.commonwidgets/configwidgets_apps.js';
-
-const MODEL_NAME = `Gemini`;
-
-export const geminiTabIcon = Icon({
- hpack: 'center',
- icon: `google-gemini-symbolic`,
-})
-
-const GeminiInfo = () => {
- const geminiLogo = Icon({
- hpack: 'center',
- className: 'sidebar-chat-welcome-logo',
- icon: `google-gemini-symbolic`,
- });
- return Box({
- vertical: true,
- className: 'spacing-v-15',
- children: [
- geminiLogo,
- Label({
- className: 'txt txt-title-small sidebar-chat-welcome-txt',
- wrap: true,
- justify: Gtk.Justification.CENTER,
- label: `Assistant (Gemini)`,
- }),
- Box({
- className: 'spacing-h-5',
- hpack: 'center',
- children: [
- Label({
- className: 'txt-smallie txt-subtext',
- wrap: true,
- justify: Gtk.Justification.CENTER,
- label: getString('Powered by Google'),
- }),
- Button({
- className: 'txt-subtext txt-norm icon-material',
- label: 'info',
- tooltipText: getString("Not affiliated, endorsed, or sponsored by Google.\n\nPrivacy: Chat messages aren't linked to your account,\nbut will be read by human reviewers to improve the model."),
- setup: setupCursorHoverInfo,
- }),
- ]
- }),
- ]
- });
-}
-
-export const GeminiSettings = () => MarginRevealer({
- transition: 'slide_down',
- revealChild: true,
- extraSetup: (self) => self
- .hook(GeminiService, (self) => Utils.timeout(200, () => {
- self.attribute.hide();
- }), 'newMsg')
- .hook(GeminiService, (self) => Utils.timeout(200, () => {
- self.attribute.show();
- }), 'clear')
- ,
- child: Box({
- vertical: true,
- className: 'sidebar-chat-settings',
- children: [
- ConfigSegmentedSelection({
- hpack: 'center',
- icon: 'casino',
- name: 'Randomness',
- desc: getString("Gemini's temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1"),
- options: [
- { value: 0.00, name: getString('Precise'), },
- { value: 0.50, name: getString('Balanced'), },
- { value: 1.00, name: getString('Creative'), },
- ],
- initIndex: 1,
- onChange: (value, name) => {
- GeminiService.temperature = value;
- },
- }),
- ConfigGap({ vertical: true, size: 10 }), // Note: size can only be 5, 10, or 15
- Box({
- vertical: true,
- hpack: 'center',
- className: 'sidebar-chat-settings-toggles',
- children: [
- AgsToggle({
- icon: 'model_training',
- name: getString('Prompt'),
- desc: getString("Tells Gemini:\n- It's a Linux sidebar assistant\n- Be brief and use bullet points"),
- option: "ai.enhancements",
- extraOnChange: (self, newValue) => {
- GeminiService.assistantPrompt = newValue;
- },
- extraOnReset: (self, newValue) => {
- GeminiService.assistantPrompt = userOptions.ai.enhancements;
- },
- }),
- AgsToggle({
- icon: 'shield',
- name: getString('Safety'),
- desc: getString("When turned off, tells the API (not the model) \nto not block harmful/explicit content"),
- option: "ai.safety",
- extraOnChange: (self, newValue) => {
- GeminiService.safe = newValue;
- },
- extraOnReset: (self, newValue) => {
- GeminiService.safe = userOptions.ai.safety;
- },
- }),
- AgsToggle({
- icon: 'history',
- name: getString('History'),
- desc: getString("Saves chat history\nMessages in previous chats won't show automatically, but they are there"),
- option: "ai.useHistory",
- extraOnChange: (self, newValue) => {
- GeminiService.useHistory = newValue;
- },
- extraOnReset: (self, newValue) => {
- GeminiService.useHistory = userOptions.ai.useHistory;
- },
- })
- ]
- })
- ]
- })
-});
-
-export const GoogleAiInstructions = () => Box({
- homogeneous: true,
- children: [Revealer({
- transition: 'slide_down',
- transitionDuration: userOptions.animations.durationLarge,
- setup: (self) => self
- .hook(GeminiService, (self, hasKey) => {
- self.revealChild = (GeminiService.key.length == 0);
- }, 'hasKey')
- ,
- child: Button({
- child: Label({
- useMarkup: true,
- wrap: true,
- className: 'txt sidebar-chat-welcome-txt',
- justify: Gtk.Justification.CENTER,
- label: 'A Google AI API key is required\nYou can grab one here, then enter it below',
- // setup: self => self.set_markup("This is a test link")
- }),
- setup: setupCursorHover,
- onClicked: () => {
- Utils.execAsync(['bash', '-c', `xdg-open https://makersuite.google.com/app/apikey &`]);
- }
- })
- })]
-});
-
-const geminiWelcome = Box({
- vexpand: true,
- homogeneous: true,
- child: Box({
- className: 'spacing-v-15 margin-top-15 margin-bottom-15',
- vpack: 'center',
- vertical: true,
- children: [
- GeminiInfo(),
- GoogleAiInstructions(),
- GeminiSettings(),
- ]
- })
-});
-
-export const chatContent = Box({
- className: 'spacing-v-5',
- vertical: true,
- setup: (self) => self
- .hook(GeminiService, (box, id) => {
- const message = GeminiService.messages[id];
- if (!message) return;
- box.add(ChatMessage(message, MODEL_NAME))
- }, 'newMsg')
- ,
-});
-
-const clearChat = () => {
- GeminiService.clear();
- const children = chatContent.get_children();
- for (let i = 0; i < children.length; i++) {
- const child = children[i];
- child.destroy();
- }
-}
-
-const CommandButton = (command) => Button({
- className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small',
- onClicked: () => sendMessage(command),
- setup: setupCursorHover,
- label: command,
-});
-
-export const geminiCommands = Box({
- className: 'spacing-h-5',
- children: [
- Box({ hexpand: true }),
- CommandButton('/key'),
- CommandButton('/model'),
- CommandButton('/clear'),
- ]
-});
-
-export const sendMessage = (text) => {
- // Check if text or API key is empty
- if (text.length == 0) return;
- if (GeminiService.key.length == 0) {
- GeminiService.key = text;
- chatContent.add(SystemMessage(`Key saved to \`${GeminiService.keyPath}\`\nUpdate anytime with /key YOUR_API_KEY.`, 'API Key', GeminiView));
- text = '';
- return;
- }
- // Commands
- if (text.startsWith('/')) {
- if (text.startsWith('/clear')) clearChat();
- else if (text.startsWith('/load')) {
- clearChat();
- GeminiService.loadHistory();
- }
- else if (text.startsWith('/model')) chatContent.add(SystemMessage(`${getString("Currently using")} \`${GeminiService.modelName}\``, '/model', GeminiView))
- else if (text.startsWith('/prompt')) {
- const firstSpaceIndex = text.indexOf(' ');
- const prompt = text.slice(firstSpaceIndex + 1);
- if (firstSpaceIndex == -1 || prompt.length < 1) {
- chatContent.add(SystemMessage(`Usage: \`/prompt MESSAGE\``, '/prompt', GeminiView))
- }
- else {
- GeminiService.addMessage('user', prompt)
- }
- }
- else if (text.startsWith('/key')) {
- const parts = text.split(' ');
- if (parts.length == 1) chatContent.add(SystemMessage(
- `${getString("Key stored in:")} \n\`${GeminiService.keyPath}\`\n${getString("To update this key, type")} \`/key YOUR_API_KEY\``,
- '/key',
- GeminiView));
- else {
- GeminiService.key = parts[1];
- chatContent.add(SystemMessage(`${getString("Updated API Key at")}\n\`${GeminiService.keyPath}\``, '/key', GeminiView));
- }
- }
- else if (text.startsWith('/test'))
- chatContent.add(SystemMessage(markdownTest, `Markdown test`, GeminiView));
- else
- chatContent.add(SystemMessage(getString(`Invalid command.`), 'Error', GeminiView))
- }
- else {
- GeminiService.send(text);
- }
-}
-
-export const GeminiView = (chatEntry) => Box({
- homogeneous: true,
- children: [Scrollable({
- className: 'sidebar-chat-viewport',
- vexpand: true,
- child: Box({
- vertical: true,
- children: [
- geminiWelcome,
- chatContent,
- ]
- }),
- setup: (scrolledWindow) => {
- // Show scrollbar
- scrolledWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
- const vScrollbar = scrolledWindow.get_vscrollbar();
- vScrollbar.get_style_context().add_class('sidebar-scrollbar');
- // Avoid click-to-scroll-widget-to-view behavior
- Utils.timeout(1, () => {
- const viewport = scrolledWindow.child;
- viewport.set_focus_vadjustment(new Gtk.Adjustment(undefined));
- })
- // Always scroll to bottom with new content
- const adjustment = scrolledWindow.get_vadjustment();
- adjustment.connect("changed", () => Utils.timeout(1, () => {
- if (!chatEntry.hasFocus) return;
- adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size());
- }))
- }
- })]
-});
\ No newline at end of file
diff --git a/.config/ags/modules/sideleft/apis/waifu.js b/.config/ags/modules/sideleft/apis/waifu.js
deleted file mode 100644
index 5a1a2c019..000000000
--- a/.config/ags/modules/sideleft/apis/waifu.js
+++ /dev/null
@@ -1,418 +0,0 @@
-// TODO: execAsync(['identify', '-format', '{"w":%w,"h":%h}', imagePath])
-// to detect img dimensions
-
-const { Gdk, GdkPixbuf, Gio, GLib, Gtk } = imports.gi;
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { Box, Button, Label, Overlay, Revealer, Scrollable, Stack } = Widget;
-const { execAsync, exec } = Utils;
-import { fileExists } from '../../.miscutils/files.js';
-import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
-import { MarginRevealer } from '../../.widgethacks/advancedrevealers.js';
-import { setupCursorHover, setupCursorHoverInfo } from '../../.widgetutils/cursorhover.js';
-import WaifuService from '../../../services/waifus.js';
-import { darkMode } from '../../.miscutils/system.js';
-
-async function getImageViewerApp(preferredApp) {
- return Utils.execAsync(['bash', '-c', `command -v ${preferredApp}`])
- .then((output) => {
- if (output != '') return preferredApp;
- else return 'xdg-open';
- })
- .catch(print);
-}
-
-const IMAGE_REVEAL_DELAY = 13; // Some wait for inits n other weird stuff
-const IMAGE_VIEWER_APP = getImageViewerApp(userOptions.apps.imageViewer); // Gnome's image viewer cuz very comfortable zooming
-const USER_CACHE_DIR = GLib.get_user_cache_dir();
-
-// Create cache folder and clear pics from previous session
-Utils.exec(`bash -c 'mkdir -p ${USER_CACHE_DIR}/ags/media/waifus'`);
-Utils.exec(`bash -c 'rm ${USER_CACHE_DIR}/ags/media/waifus/*'`);
-
-const CommandButton = (command) => Button({
- className: 'sidebar-chat-chip sidebar-chat-chip-action txt txt-small',
- onClicked: () => sendMessage(command),
- setup: setupCursorHover,
- label: command,
-});
-
-export const waifuTabIcon = Box({
- hpack: 'center',
- children: [
- MaterialIcon('photo', 'norm'),
- ]
-});
-
-const WaifuInfo = () => {
- const waifuLogo = Label({
- hpack: 'center',
- className: 'sidebar-chat-welcome-logo',
- label: 'photo',
- })
- return Box({
- vertical: true,
- vexpand: true,
- className: 'spacing-v-15',
- children: [
- waifuLogo,
- Label({
- className: 'txt txt-title-small sidebar-chat-welcome-txt',
- wrap: true,
- justify: Gtk.Justification.CENTER,
- label: 'Waifus',
- }),
- Box({
- className: 'spacing-h-5',
- hpack: 'center',
- children: [
- Label({
- className: 'txt-smallie txt-subtext',
- wrap: true,
- justify: Gtk.Justification.CENTER,
- label: getString('Powered by waifu.im + other APIs'),
- }),
- Button({
- className: 'txt-subtext txt-norm icon-material',
- label: 'info',
- tooltipText: getString('Type tags for a random pic.\nNSFW content will not be returned unless\nyou explicitly request such a tag.\n\nDisclaimer: Not affiliated with the providers\nnor responsible for any of their content.'),
- setup: setupCursorHoverInfo,
- }),
- ]
- }),
- ]
- });
-}
-
-const waifuWelcome = Box({
- vexpand: true,
- homogeneous: true,
- child: Box({
- className: 'spacing-v-15 margin-top-15 margin-bottom-15',
- vpack: 'center',
- vertical: true,
- children: [
- WaifuInfo(),
- ]
- })
-});
-
-const WaifuImage = (taglist) => {
- const ImageState = (icon, name) => Box({
- className: 'spacing-h-5 txt',
- children: [
- Box({ hexpand: true }),
- Label({
- className: 'sidebar-waifu-txt txt-smallie',
- xalign: 0,
- label: name,
- }),
- MaterialIcon(icon, 'norm'),
- ]
- })
- const ImageAction = ({ name, icon, action }) => Button({
- className: 'sidebar-waifu-image-action txt-norm icon-material',
- tooltipText: name,
- label: icon,
- onClicked: action,
- setup: setupCursorHover,
- })
- const downloadState = Stack({
- homogeneous: false,
- transition: 'slide_up_down',
- transitionDuration: userOptions.animations.durationSmall,
- children: {
- 'api': ImageState('api', getString('Calling API')),
- 'download': ImageState('downloading', getString('Downloading image')),
- 'done': ImageState('done', getString('Finished!')),
- 'error': ImageState('error', getString('Error')),
- 'notfound': ImageState('error', getString('Not found!')),
- },
- });
- const downloadIndicator = MarginRevealer({
- vpack: 'center',
- transition: 'slide_left',
- revealChild: true,
- child: downloadState,
- });
- const blockHeading = Box({
- hpack: 'fill',
- className: 'spacing-h-5',
- children: [
- ...taglist.map((tag) => CommandButton(tag)),
- Box({ hexpand: true }),
- downloadIndicator,
- ]
- });
- const blockImageActions = Revealer({
- transition: 'crossfade',
- revealChild: false,
- child: Box({
- vertical: true,
- children: [
- Box({
- className: 'sidebar-waifu-image-actions spacing-h-3',
- children: [
- Box({ hexpand: true }),
- ImageAction({
- name: getString('Go to source'),
- icon: 'link',
- action: () => execAsync(['xdg-open', `${thisBlock.attribute.imageData.source}`]).catch(print),
- }),
- ImageAction({
- name: getString('Hoard'),
- icon: 'save',
- action: (self) => {
- execAsync(['bash', '-c', `mkdir -p $(xdg-user-dir PICTURES)/homework${thisBlock.attribute.isNsfw ? '/🌶️' : ''} && cp ${thisBlock.attribute.imagePath} $(xdg-user-dir PICTURES)/homework${thisBlock.attribute.isNsfw ? '/🌶️/' : ''}`])
- .then(() => self.label = 'done')
- .catch(print);
- },
- }),
- ImageAction({
- name: getString('Open externally'),
- icon: 'open_in_new',
- action: () => execAsync([IMAGE_VIEWER_APP, `${thisBlock.attribute.imagePath}`]).catch(print),
- }),
- ]
- })
- ],
- })
- })
- const blockImage = Widget.DrawingArea({
- className: 'sidebar-waifu-image',
- });
- const blockImageRevealer = Revealer({
- transition: 'slide_down',
- transitionDuration: userOptions.animations.durationLarge,
- revealChild: false,
- child: Box({
- className: 'margin-top-5',
- children: [Overlay({
- child: Box({
- homogeneous: true,
- className: 'sidebar-waifu-image',
- children: [blockImage],
- }),
- overlays: [blockImageActions],
- })]
- }),
- });
- const thisBlock = Box({
- className: 'sidebar-chat-message',
- attribute: {
- 'imagePath': '',
- 'isNsfw': false,
- 'imageData': '',
- 'update': (imageData, force = false) => {
- thisBlock.attribute.imageData = imageData;
- const { status, signature, url, extension, source, dominant_color, is_nsfw, width, height, tags } = thisBlock.attribute.imageData;
- thisBlock.attribute.isNsfw = is_nsfw;
- if (status == 404) {
- downloadState.shown = 'notfound';
- return;
- }
- if (status != 200) {
- downloadState.shown = 'error';
- return;
- }
- thisBlock.attribute.imagePath = `${USER_CACHE_DIR}/ags/media/waifus/${signature}${extension}`;
- downloadState.shown = 'download';
- // Width/height
- const widgetWidth = Math.min(Math.floor(waifuContent.get_allocated_width() * 0.85), width);
- const widgetHeight = Math.ceil(widgetWidth * height / width);
- blockImage.set_size_request(widgetWidth, widgetHeight);
- const showImage = () => {
- downloadState.shown = 'done';
- const pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(thisBlock.attribute.imagePath, widgetWidth, widgetHeight);
- // const pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(thisBlock.attribute.imagePath, widgetWidth, widgetHeight, false);
-
- blockImage.set_size_request(widgetWidth, widgetHeight);
- blockImage.connect("draw", (widget, cr) => {
- const borderRadius = widget.get_style_context().get_property('border-radius', Gtk.StateFlags.NORMAL);
-
- // Draw a rounded rectangle
- cr.arc(borderRadius, borderRadius, borderRadius, Math.PI, 1.5 * Math.PI);
- cr.arc(widgetWidth - borderRadius, borderRadius, borderRadius, 1.5 * Math.PI, 2 * Math.PI);
- cr.arc(widgetWidth - borderRadius, widgetHeight - borderRadius, borderRadius, 0, 0.5 * Math.PI);
- cr.arc(borderRadius, widgetHeight - borderRadius, borderRadius, 0.5 * Math.PI, Math.PI);
- cr.closePath();
- cr.clip();
-
- // Paint image as bg
- Gdk.cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
- cr.paint();
- });
-
- // Reveal stuff
- Utils.timeout(IMAGE_REVEAL_DELAY, () => {
- blockImageRevealer.revealChild = true;
- })
- Utils.timeout(IMAGE_REVEAL_DELAY + blockImageRevealer.transitionDuration,
- () => blockImageActions.revealChild = true
- );
- downloadIndicator.attribute.hide();
- }
- // Show
- if (!force && fileExists(thisBlock.attribute.imagePath)) showImage();
- else Utils.execAsync(['bash', '-c', `wget -O '${thisBlock.attribute.imagePath}' '${url}'`])
- .then(showImage)
- .catch(print);
- thisBlock.css = `background-color: mix(${darkMode.value ? 'black' : 'white'}, ${dominant_color}, 0.97);`;
- },
- },
- children: [
- Box({
- vertical: true,
- children: [
- blockHeading,
- Box({
- vertical: true,
- hpack: 'start',
- children: [blockImageRevealer],
- })
- ]
- })
- ],
- });
- return thisBlock;
-}
-
-const waifuContent = Box({
- className: 'spacing-v-15',
- vertical: true,
- attribute: {
- 'map': new Map(),
- },
- setup: (self) => self
- .hook(WaifuService, (box, id) => {
- if (id === undefined) return;
- const newImageBlock = WaifuImage(WaifuService.queries[id]);
- box.add(newImageBlock);
- box.show_all();
- box.attribute.map.set(id, newImageBlock);
- }, 'newResponse')
- .hook(WaifuService, (box, id) => {
- if (id === undefined) return;
- const data = WaifuService.responses[id];
- if (!data) return;
- const imageBlock = box.attribute.map.get(id);
- imageBlock?.attribute.update(data);
- }, 'updateResponse')
- ,
-});
-
-export const WaifuView = (chatEntry) => Scrollable({
- className: 'sidebar-chat-viewport',
- vexpand: true,
- child: Box({
- vertical: true,
- children: [
- waifuWelcome,
- waifuContent,
- ]
- }),
- setup: (scrolledWindow) => {
- // Show scrollbar
- scrolledWindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
- const vScrollbar = scrolledWindow.get_vscrollbar();
- vScrollbar.get_style_context().add_class('sidebar-scrollbar');
- // Avoid click-to-scroll-widget-to-view behavior
- Utils.timeout(1, () => {
- const viewport = scrolledWindow.child;
- viewport.set_focus_vadjustment(new Gtk.Adjustment(undefined));
- })
- // Always scroll to bottom with new content
- const adjustment = scrolledWindow.get_vadjustment();
- adjustment.connect("changed", () => {
- if (!chatEntry.hasFocus) return;
- adjustment.set_value(adjustment.get_upper() - adjustment.get_page_size());
- })
- }
-});
-
-const waifuTags = Revealer({
- revealChild: false,
- transition: 'crossfade',
- transitionDuration: userOptions.animations.durationLarge,
- child: Box({
- className: 'spacing-h-5',
- children: [
- Scrollable({
- vscroll: 'never',
- hscroll: 'automatic',
- hexpand: true,
- child: Box({
- className: 'spacing-h-5',
- children: [
- CommandButton('waifu'),
- CommandButton('maid'),
- CommandButton('uniform'),
- CommandButton('oppai'),
- CommandButton('selfies'),
- CommandButton('marin-kitagawa'),
- CommandButton('raiden-shogun'),
- CommandButton('mori-calliope'),
- ]
- })
- }),
- Box({ className: 'separator-line' }),
- ]
- })
-});
-
-export const waifuCommands = Box({
- className: 'spacing-h-5',
- setup: (self) => {
- self.pack_end(CommandButton('/clear'), false, false, 0);
- self.pack_start(Button({
- className: 'sidebar-chat-chip-toggle',
- setup: setupCursorHover,
- label: getString('Tags →'),
- onClicked: () => {
- waifuTags.revealChild = !waifuTags.revealChild;
- }
- }), false, false, 0);
- self.pack_start(waifuTags, true, true, 0);
- }
-});
-
-const clearChat = () => { // destroy!!
- waifuContent.attribute.map.forEach((value, key, map) => {
- value.destroy();
- value = null;
- });
-}
-
-function newSimpleImageCall(name, url, width, height, dominantColor = '#9392A6') {
- const timeSinceEpoch = Date.now();
- const newImage = WaifuImage([`/${name}`]);
- waifuContent.add(newImage);
- waifuContent.attribute.map.set(timeSinceEpoch, newImage);
- Utils.timeout(IMAGE_REVEAL_DELAY, () => newImage?.attribute.update({
- status: 200,
- url: url,
- extension: '',
- signature: timeSinceEpoch,
- source: url,
- dominant_color: dominantColor,
- is_nsfw: false,
- width: width,
- height: height,
- tags: [`/${name}`],
- }, true));
-}
-
-export const sendMessage = (text) => {
- // Commands
- if (text.startsWith('/')) {
- if (text.startsWith('/clear')) clearChat();
- else if (text.startsWith('/test'))
- newSimpleImageCall('test', 'https://picsum.photos/600/400', 300, 200);
- else if (text.startsWith('/chino'))
- newSimpleImageCall('chino', 'https://chino.pages.dev/chino', 300, 400, '#B2AEF3');
- else if (text.startsWith('/place'))
- newSimpleImageCall('place', 'https://placewaifu.com/image/400/600', 400, 600, '#F0A235');
-
- }
- else WaifuService.fetch(text);
-}
diff --git a/.config/ags/modules/sideleft/apiwidgets.js b/.config/ags/modules/sideleft/apiwidgets.js
deleted file mode 100644
index 17b7576ab..000000000
--- a/.config/ags/modules/sideleft/apiwidgets.js
+++ /dev/null
@@ -1,243 +0,0 @@
-const { Gtk, Gdk } = imports.gi;
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { Box, Button, CenterBox, Entry, EventBox, Icon, Label, Overlay, Revealer, Scrollable, Stack } = Widget;
-const { execAsync, exec } = Utils;
-import { setupCursorHover } from '../.widgetutils/cursorhover.js';
-// APIs
-import GPTService from '../../services/gpt.js';
-import Gemini from '../../services/gemini.js';
-import { GeminiView, geminiCommands, sendMessage as geminiSendMessage, geminiTabIcon } from './apis/gemini.js';
-import { ChatGPTView, chatGPTCommands, sendMessage as chatGPTSendMessage, chatGPTTabIcon } from './apis/chatgpt.js';
-import { WaifuView, waifuCommands, sendMessage as waifuSendMessage, waifuTabIcon } from './apis/waifu.js';
-import { BooruView, booruCommands, sendMessage as booruSendMessage, booruTabIcon } from './apis/booru.js';
-import { enableClickthrough } from "../.widgetutils/clickthrough.js";
-import { checkKeybind } from '../.widgetutils/keybind.js';
-const TextView = Widget.subclass(Gtk.TextView, "AgsTextView");
-
-import { widgetContent } from './sideleft.js';
-import { IconTabContainer } from '../.commonwidgets/tabcontainer.js';
-import { updateNestedProperty } from '../.miscutils/objects.js';
-
-const EXPAND_INPUT_THRESHOLD = 30;
-const AGS_CONFIG_FILE = `${App.configDir}/user_options.jsonc`;
-
-export const chatEntry = TextView({
- hexpand: true,
- wrapMode: Gtk.WrapMode.WORD_CHAR,
- acceptsTab: false,
- className: 'sidebar-chat-entry txt txt-smallie',
- setup: (self) => self
- .hook(App, (self, currentName, visible) => {
- if (visible && currentName === 'sideleft') {
- self.grab_focus();
- }
- })
- .hook(GPTService, (self) => {
- if (APIS[currentApiId].name != 'Assistant (GPTs)') return;
- self.placeholderText = (GPTService.key.length > 0 ? getString('Message the model...') : getString('Enter API Key...'));
- }, 'hasKey')
- .hook(Gemini, (self) => {
- if (APIS[currentApiId].name != 'Assistant (Gemini Pro)') return;
- self.placeholderText = (Gemini.key.length > 0 ? getString('Message Gemini...') : getString('Enter Google AI API Key...'));
- }, 'hasKey')
- .on("key-press-event", (widget, event) => {
- // Don't send when Shift+Enter
- if (event.get_keyval()[1] === Gdk.KEY_Return || event.get_keyval()[1] === Gdk.KEY_KP_Enter) {
- if (event.get_state()[1] !== 17) {// SHIFT_MASK doesn't work but 17 should be shift
- apiSendMessage(widget);
- return true;
- }
- return false;
- }
- // Keybinds
- if (checkKeybind(event, userOptions.keybinds.sidebar.cycleTab))
- widgetContent.cycleTab();
- else if (checkKeybind(event, userOptions.keybinds.sidebar.nextTab))
- widgetContent.nextTab();
- else if (checkKeybind(event, userOptions.keybinds.sidebar.prevTab))
- widgetContent.prevTab();
- else if (checkKeybind(event, userOptions.keybinds.sidebar.apis.nextTab)) {
- apiWidgets.attribute.nextTab();
- return true;
- }
- else if (checkKeybind(event, userOptions.keybinds.sidebar.apis.prevTab)) {
- apiWidgets.attribute.prevTab();
- return true;
- }
- })
- ,
-});
-
-const APILIST = {
- 'gemini': {
- "name": 'Assistant (Gemini Pro)',
- "sendCommand": geminiSendMessage,
- "contentWidget": GeminiView(chatEntry),
- "commandBar": geminiCommands,
- "tabIcon": geminiTabIcon,
- "placeholderText": getString('Message Gemini...'),
- },
- 'gpt': {
- "name": 'Assistant (GPTs)',
- "sendCommand": chatGPTSendMessage,
- "contentWidget": ChatGPTView(chatEntry),
- "commandBar": chatGPTCommands,
- "tabIcon": chatGPTTabIcon,
- "placeholderText": getString('Message the model...'),
- },
- 'waifu': {
- "name": 'Waifus',
- "sendCommand": waifuSendMessage,
- "contentWidget": WaifuView(chatEntry),
- "commandBar": waifuCommands,
- "tabIcon": waifuTabIcon,
- "placeholderText": getString('Enter tags'),
- },
- 'booru': {
- "name": 'Booru',
- "sendCommand": booruSendMessage,
- "contentWidget": BooruView(chatEntry),
- "commandBar": booruCommands,
- "tabIcon": booruTabIcon,
- "placeholderText": getString('Enter tags and/or page number'),
- },
-}
-const APIS = userOptions.sidebar.pages.apis.order.map((apiName) => {
- const obj = { ...APILIST[apiName] };
- obj["id"] = apiName;
- return obj;
-});
-let currentApiId = APIS.findIndex(obj => obj.id === userOptions.sidebar.pages.apis.defaultPage);
-
-function apiSendMessage(textView) {
- // Get text
- const buffer = textView.get_buffer();
- const [start, end] = buffer.get_bounds();
- const text = buffer.get_text(start, end, true).trimStart();
- if (!text || text.length == 0) return;
- // Send
- if (APIS[currentApiId].name == APILIST['booru'].name)
- APIS[currentApiId].sendCommand(text, APILIST['booru'].contentWidget)
- else
- APIS[currentApiId].sendCommand(text)
- // Reset
- buffer.set_text("", -1);
- chatEntryWrapper.toggleClassName('sidebar-chat-wrapper-extended', false);
- chatEntry.set_valign(Gtk.Align.CENTER);
-}
-
-chatEntry.get_buffer().connect("changed", (buffer) => {
- const bufferText = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), true);
- chatSendButton.toggleClassName('sidebar-chat-send-available', bufferText.length > 0);
- chatPlaceholderRevealer.revealChild = (bufferText.length == 0);
- if (buffer.get_line_count() > 1 || bufferText.length > EXPAND_INPUT_THRESHOLD) {
- chatEntryWrapper.toggleClassName('sidebar-chat-wrapper-extended', true);
- chatEntry.set_valign(Gtk.Align.FILL);
- chatPlaceholder.set_valign(Gtk.Align.FILL);
- }
- else {
- chatEntryWrapper.toggleClassName('sidebar-chat-wrapper-extended', false);
- chatEntry.set_valign(Gtk.Align.CENTER);
- chatPlaceholder.set_valign(Gtk.Align.CENTER);
- }
-});
-
-const chatEntryWrapper = Scrollable({
- className: 'sidebar-chat-wrapper',
- hscroll: 'never',
- vscroll: 'always',
- child: chatEntry,
-});
-
-const chatSendButton = Button({
- className: 'txt-norm icon-material sidebar-chat-send',
- vpack: 'end',
- label: 'arrow_upward',
- setup: setupCursorHover,
- onClicked: (self) => {
- APIS[currentApiId].sendCommand(chatEntry.get_buffer().text);
- chatEntry.get_buffer().set_text("", -1);
- },
-});
-
-const chatPlaceholder = Label({
- className: 'txt-subtext txt-smallie margin-left-5',
- hpack: 'start',
- vpack: 'center',
- label: APIS[currentApiId].placeholderText,
-});
-
-const chatPlaceholderRevealer = Revealer({
- revealChild: true,
- transition: 'crossfade',
- transitionDuration: userOptions.animations.durationLarge,
- child: chatPlaceholder,
- setup: enableClickthrough,
-});
-
-const textboxArea = Box({ // Entry area
- className: 'sidebar-chat-textarea',
- children: [
- Overlay({
- passThrough: true,
- child: chatEntryWrapper,
- overlays: [chatPlaceholderRevealer],
- }),
- Box({ className: 'width-10' }),
- chatSendButton,
- ]
-});
-
-const apiCommandStack = Stack({
- transition: 'slide_up_down',
- transitionDuration: userOptions.animations.durationLarge,
- children: APIS.reduce((acc, api) => {
- acc[api.name] = api.commandBar;
- return acc;
- }, {}),
-})
-
-export const apiContentStack = IconTabContainer({
- tabSwitcherClassName: 'sidebar-icontabswitcher',
- className: 'margin-top-5',
- iconWidgets: APIS.map((api) => api.tabIcon),
- names: APIS.map((api) => api.name),
- children: APIS.map((api) => api.contentWidget),
- initIndex: currentApiId,
- onChange: (self, id) => {
- apiCommandStack.shown = APIS[id].name;
- chatPlaceholder.label = APIS[id].placeholderText;
- currentApiId = id;
- const pageName = APIS[id].id;
- const option = 'sidebar.pages.apis.defaultPage';
- updateNestedProperty(userOptions, option, pageName);
- execAsync(['bash', '-c', `${App.configDir}/scripts/ags/agsconfigurator.py \
- --key ${option} \
- --value ${pageName} \
- --file ${AGS_CONFIG_FILE}`
- ]).catch(print);
- }
-
-});
-
-function switchToTab(id) {
- apiContentStack.shown.value = id;
-}
-
-const apiWidgets = Widget.Box({
- attribute: {
- 'nextTab': () => switchToTab(Math.min(currentApiId + 1, APIS.length - 1)),
- 'prevTab': () => switchToTab(Math.max(0, currentApiId - 1)),
- },
- vertical: true,
- className: 'spacing-v-10',
- homogeneous: false,
- children: [
- apiContentStack,
- apiCommandStack,
- textboxArea,
- ],
-});
-
-export default apiWidgets;
diff --git a/.config/ags/modules/sideleft/main.js b/.config/ags/modules/sideleft/main.js
deleted file mode 100644
index dd52ac07d..000000000
--- a/.config/ags/modules/sideleft/main.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import PopupWindow from '../.widgethacks/popupwindow.js';
-import SidebarLeft from "./sideleft.js";
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-const { Box } = Widget;
-import clickCloseRegion from '../.commonwidgets/clickcloseregion.js';
-
-export default () => PopupWindow({
- keymode: 'on-demand',
- anchor: ['left', 'top', 'bottom'],
- name: 'sideleft',
- layer: 'top',
- child: Box({
- children: [
- SidebarLeft(),
- clickCloseRegion({ name: 'sideleft', multimonitor: false, fillMonitor: 'horizontal' }),
- ]
- })
-});
diff --git a/.config/ags/modules/sideleft/sideleft.js b/.config/ags/modules/sideleft/sideleft.js
deleted file mode 100644
index 0b276d0af..000000000
--- a/.config/ags/modules/sideleft/sideleft.js
+++ /dev/null
@@ -1,158 +0,0 @@
-const { Gdk } = imports.gi;
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { Box, Button, EventBox, Label, Revealer, Scrollable, Stack } = Widget;
-const { execAsync, exec } = Utils;
-import { MaterialIcon } from '../.commonwidgets/materialicon.js';
-import { setupCursorHover } from '../.widgetutils/cursorhover.js';
-import toolBox from './toolbox.js';
-import apiWidgets from './apiwidgets.js';
-import { chatEntry } from './apiwidgets.js';
-import { TabContainer } from '../.commonwidgets/tabcontainer.js';
-import { checkKeybind } from '../.widgetutils/keybind.js';
-import { updateNestedProperty } from '../.miscutils/objects.js';
-
-const AGS_CONFIG_FILE = `${App.configDir}/user_options.jsonc`;
-
-const SIDEBARTABS = {
- 'apis': {
- name: 'apis',
- content: apiWidgets,
- materialIcon: 'api',
- friendlyName: 'APIs',
- },
- 'tools': {
- name: 'tools',
- content: toolBox,
- materialIcon: 'home_repair_service',
- friendlyName: 'Tools',
- },
-}
-const CONTENTS = userOptions.sidebar.pages.order.map((tabName) => SIDEBARTABS[tabName])
-
-// const pinButton = Button({
-// attribute: {
-// 'enabled': false,
-// 'toggle': (self) => {
-// self.attribute.enabled = !self.attribute.enabled;
-// self.toggleClassName('sidebar-controlbtn-enabled', self.attribute.enabled);
-
-// const sideleftWindow = App.getWindow('sideleft');
-// const sideleftContent = sideleftWindow.get_children()[0].get_children()[0].get_children()[1];
-
-// sideleftContent.toggleClassName('sidebar-pinned', self.attribute.enabled);
-
-// if (self.attribute.enabled) {
-// sideleftWindow.exclusivity = 'exclusive';
-// }
-// else {
-// sideleftWindow.exclusivity = 'normal';
-// }
-// },
-// },
-// vpack: 'start',
-// className: 'sidebar-controlbtn',
-// child: MaterialIcon('push_pin', 'larger'),
-// tooltipText: `Pin sidebar (${userOptions.keybinds.sidebar.pin})`,
-// onClicked: (self) => self.attribute.toggle(self),
-// setup: (self) => {
-// setupCursorHover(self);
-// self.hook(App, (self, currentName, visible) => {
-// if (currentName === 'sideleft' && visible) self.grab_focus();
-// })
-// },
-// })
-
-const expandButton = Button({
- attribute: {
- 'enabled': false,
- 'toggle': (self) => {
- self.attribute.enabled = !self.attribute.enabled;
- // We don't expand the bar, but the expand button. Funny hax but it works
- // (somehow directly expanding the sidebar directly makes it unable to unexpand)
- self.toggleClassName('sidebar-expandbtn-enabled', self.attribute.enabled);
- self.toggleClassName('sidebar-controlbtn-enabled', self.attribute.enabled);
- },
- },
- vpack: 'start',
- className: 'sidebar-controlbtn',
- child: MaterialIcon('expand_content', 'larger'),
- tooltipText: `Expand sidebar (${userOptions.keybinds.sidebar.expand})`,
- onClicked: (self) => self.attribute.toggle(self),
- setup: setupCursorHover,
-})
-
-export const widgetContent = TabContainer({
- icons: CONTENTS.map((item) => item.materialIcon),
- names: CONTENTS.map((item) => item.friendlyName),
- children: CONTENTS.map((item) => item.content),
- className: 'sidebar-left spacing-v-10',
- initIndex: CONTENTS.findIndex(obj => obj.name === userOptions.sidebar.pages.defaultPage),
- onChange: (self, index) => {
- const pageName = CONTENTS[index].name;
- const option = 'sidebar.pages.defaultPage';
- updateNestedProperty(userOptions, option, pageName);
- execAsync(['bash', '-c', `${App.configDir}/scripts/ags/agsconfigurator.py \
- --key ${option} \
- --value ${pageName} \
- --file ${AGS_CONFIG_FILE}`
- ]).catch(print);
- },
- extraTabStripWidgets: [
- // pinButton,
- expandButton,
- ]
-});
-
-export default () => {
- return Box({
- // vertical: true,
- vexpand: true,
- css: 'min-width: 2px;',
- children: [
- widgetContent,
- ],
- setup: (self) => self
- .on('key-press-event', (widget, event) => { // Handle keybinds
- if (checkKeybind(event, userOptions.keybinds.sidebar.cycleTab))
- widgetContent.cycleTab();
- else if (checkKeybind(event, userOptions.keybinds.sidebar.nextTab))
- widgetContent.nextTab();
- else if (checkKeybind(event, userOptions.keybinds.sidebar.prevTab))
- widgetContent.prevTab();
- else if (checkKeybind(event, userOptions.keybinds.sidebar.expand))
- expandButton.attribute.toggle(expandButton);
- // if (checkKeybind(event, userOptions.keybinds.sidebar.pin))
- // pinButton.attribute.toggle(pinButton);
-
- if (widgetContent.attribute.names[widgetContent.attribute.shown.value] == 'APIs') { // If api tab is focused
- // Focus entry when typing
- if ((
- !(event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) &&
- event.get_keyval()[1] >= 32 && event.get_keyval()[1] <= 126 &&
- widget != chatEntry && event.get_keyval()[1] != Gdk.KEY_space)
- ||
- ((event.get_state()[1] & Gdk.ModifierType.CONTROL_MASK) &&
- event.get_keyval()[1] === Gdk.KEY_v)
- ) {
- chatEntry.grab_focus();
- const buffer = chatEntry.get_buffer();
- buffer.set_text(buffer.text + String.fromCharCode(event.get_keyval()[1]), -1);
- buffer.place_cursor(buffer.get_iter_at_offset(-1));
- }
- // Switch API type
- else if (checkKeybind(event, userOptions.keybinds.sidebar.apis.nextTab)) {
- const toSwitchTab = widgetContent.attribute.children[widgetContent.attribute.shown.value];
- toSwitchTab.nextTab();
- }
- else if (checkKeybind(event, userOptions.keybinds.sidebar.apis.prevTab)) {
- const toSwitchTab = widgetContent.attribute.children[widgetContent.attribute.shown.value];
- toSwitchTab.prevTab();
- }
- }
-
- })
- ,
- });
-}
diff --git a/.config/ags/modules/sideleft/toolbox.js b/.config/ags/modules/sideleft/toolbox.js
deleted file mode 100644
index 879082fde..000000000
--- a/.config/ags/modules/sideleft/toolbox.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-const { Box, Label, Scrollable } = Widget;
-import QuickScripts from './tools/quickscripts.js';
-import ColorPicker from './tools/colorpicker.js';
-import Conversions from './tools/conversions.js';
-import Name from './tools/name.js';
-
-export default Scrollable({
- hscroll: "never",
- vscroll: "automatic",
- child: Box({
- vertical: true,
- className: 'spacing-v-10',
- children: [
- QuickScripts(),
- Conversions(),
- ColorPicker(),
- Box({ vexpand: true }),
- Name(),
- ]
- })
-});
diff --git a/.config/ags/modules/sideleft/tools/changeres.sh b/.config/ags/modules/sideleft/tools/changeres.sh
deleted file mode 100644
index 333f09881..000000000
--- a/.config/ags/modules/sideleft/tools/changeres.sh
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/bin/bash
-
-# Function to get the current resolution
-get_current_resolution() {
- local output
- output=$(hyprctl monitors -j)
- local width height refreshRate
- width=$(echo "$output" | jq -r '.[0].width')
- height=$(echo "$output" | jq -r '.[0].height')
- refreshRate=$(echo "$output" | jq -r '.[0].refreshRate')
- echo "$width $height $refreshRate"
-}
-
-# Function to update the Hyprland configuration with the new resolution
-update_resolution_config() {
- local newWidth="$1"
- local newHeight="$2"
- local newRefreshRate="$3"
- local currentRes
- currentRes=$(get_current_resolution)
- local width height refreshRate
- width=${newWidth:-$(echo "$currentRes" | awk '{print $1}')}
- height=${newHeight:-$(echo "$currentRes" | awk '{print $2}')}
- refreshRate=${newRefreshRate:-$(echo "$currentRes" | awk '{print $3}')}
-
- local modelineOutput
- modelineOutput=$(gtf "$width" "$height" "$refreshRate")
- local modeline
- modeline=$(echo "$modelineOutput" | grep -oP 'Modeline "\K[^"]+')
-
- if [ -z "$modeline" ]; then
- echo "Failed to generate modeline"
- exit 1
- fi
-
- # Extract the resolution and refresh rate from the modeline
- local resolution
- resolution=$(echo "$modeline" | grep -oP '^[0-9]+x[0-9]+')
- local rate
- rate=$(echo "$modeline" | grep -oP '[0-9]+.[0-9]+$')
-
- if [ -z "$resolution" ] || [ -z "$rate" ]; then
- echo "Failed to extract resolution or refresh rate from modeline"
- exit 1
- fi
-
- local configPath="${HOME}/.config/hypr/hyprland/general.conf"
- local newConfigContent
- newConfigContent=$(sed "s/^monitor=.*$/monitor=eDP-1, $resolution@$rate, auto, 1/" "$configPath")
-
- echo "$newConfigContent" > "$configPath"
-}
-
-# Main script
-echo "Welcome to the Resolution Configurator"
-echo ""
-echo " +---------------------------+"
-echo " | _____ |"
-echo " | | | |"
-echo " | | | |"
-echo " | |_____| |"
-echo " | |"
-echo " +---------------------------+"
-echo ""
-echo "Current resolution and refresh rate:"
-currentRes=$(get_current_resolution)
-width=$(echo "$currentRes" | awk '{print $1}')
-height=$(echo "$currentRes" | awk '{print $2}')
-refreshRate=$(echo "$currentRes" | awk '{print $3}')
-
-echo "Width: $width px"
-echo "Height: $height px"
-echo "Refresh Rate: $refreshRate Hz"
-
-echo ""
-
-read -p "Enter new width (or press Enter to keep current width): " newWidth
-read -p "Enter new height (or press Enter to keep current height): " newHeight
-read -p "Enter new refresh rate (or press Enter to keep current refresh rate): " newRefreshRate
-
-# Validate inputs (if provided)
-if [[ ! "$newWidth" =~ ^[0-9]+$ && -n "$newWidth" ]]; then
- echo "Invalid width value."
- exit 1
-fi
-
-if [[ ! "$newHeight" =~ ^[0-9]+$ && -n "$newHeight" ]]; then
- echo "Invalid height value."
- exit 1
-fi
-
-if [[ ! "$newRefreshRate" =~ ^[0-9]+$ && -n "$newRefreshRate" ]]; then
- echo "Invalid refresh rate value."
- exit 1
-fi
-
-update_resolution_config "$newWidth" "$newHeight" "$newRefreshRate"
-
-echo "Resolution updated successfully."
diff --git a/.config/ags/modules/sideleft/tools/color.js b/.config/ags/modules/sideleft/tools/color.js
deleted file mode 100644
index 568a04c33..000000000
--- a/.config/ags/modules/sideleft/tools/color.js
+++ /dev/null
@@ -1,198 +0,0 @@
-// It's weird, I know
-const { Gio, GLib } = imports.gi;
-import Service from 'resource:///com/github/Aylur/ags/service.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { exec, execAsync } = Utils;
-import { clamp } from '../../.miscutils/mathfuncs.js';
-
-export class ColorPickerSelection extends Service {
- static {
- Service.register(this, {
- 'picked': [],
- 'assigned': ['int'],
- 'hue': [],
- 'sl': [],
- });
- }
-
- _hue = 198;
- _xAxis = 94;
- _yAxis = 80;
-
- get hue() { return this._hue; }
- set hue(value) {
- this._hue = clamp(value, 0, 360);
- this.emit('hue');
- this.emit('picked');
- this.emit('changed');
- }
- get xAxis() { return this._xAxis; }
- set xAxis(value) {
- this._xAxis = clamp(value, 0, 100);
- this.emit('sl');
- this.emit('picked');
- this.emit('changed');
- }
- get yAxis() { return this._yAxis; }
- set yAxis(value) {
- this._yAxis = clamp(value, 0, 100);
- this.emit('sl');
- this.emit('picked');
- this.emit('changed');
- }
- setColorFromHex(hexString, id) {
- const hsl = hexToHSL(hexString);
- this._hue = hsl.hue;
- this._xAxis = hsl.saturation;
- // this._yAxis = hsl.lightness;
- this._yAxis = (100 - hsl.saturation / 2) / 100 * hsl.lightness;
- // console.log(this._hue, this._xAxis, this._yAxis)
- this.emit('assigned', id);
- this.emit('changed');
- }
-
- constructor() {
- super();
- this.emit('changed');
- }
-}
-
-
-export function hslToRgbValues(h, s, l) {
- h /= 360;
- s /= 100;
- l /= 100;
- let r, g, b;
- if (s === 0) {
- r = g = b = l; // achromatic
- } else {
- const hue2rgb = (p, q, t) => {
- if (t < 0) t += 1;
- if (t > 1) t -= 1;
- if (t < 1 / 6) return p + (q - p) * 6 * t;
- if (t < 1 / 2) return q;
- if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
- return p;
- };
- const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
- const p = 2 * l - q;
- r = hue2rgb(p, q, h + 1 / 3);
- g = hue2rgb(p, q, h);
- b = hue2rgb(p, q, h - 1 / 3);
- }
- const to255 = x => Math.round(x * 255);
- r = to255(r);
- g = to255(g);
- b = to255(b);
- return `${Math.round(r)},${Math.round(g)},${Math.round(b)}`;
- // return `rgb(${r},${g},${b})`;
-}
-export function hslToHex(h, s, l) {
- h /= 360;
- s /= 100;
- l /= 100;
- let r, g, b;
- if (s === 0) {
- r = g = b = l; // achromatic
- } else {
- const hue2rgb = (p, q, t) => {
- if (t < 0) t += 1;
- if (t > 1) t -= 1;
- if (t < 1 / 6) return p + (q - p) * 6 * t;
- if (t < 1 / 2) return q;
- if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
- return p;
- };
- const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
- const p = 2 * l - q;
- r = hue2rgb(p, q, h + 1 / 3);
- g = hue2rgb(p, q, h);
- b = hue2rgb(p, q, h - 1 / 3);
- }
- const toHex = x => {
- const hex = Math.round(x * 255).toString(16);
- return hex.length === 1 ? "0" + hex : hex;
- };
- return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
-}
-
-// export function hexToHSL(hex) {
-// // Remove the '#' if present
-// hex = hex.replace(/^#/, '');
-// // Parse the hex value into RGB components
-// const bigint = parseInt(hex, 16);
-// const r = (bigint >> 16) & 255;
-// const g = (bigint >> 8) & 255;
-// const b = bigint & 255;
-// // Normalize RGB values to range [0, 1]
-// const normalizedR = r / 255;
-// const normalizedG = g / 255;
-// const normalizedB = b / 255;
-// // Find the maximum and minimum values
-// const max = Math.max(normalizedR, normalizedG, normalizedB);
-// const min = Math.min(normalizedR, normalizedG, normalizedB);
-// // Calculate the lightness
-// const lightness = (max + min) / 2;
-// // If the color is grayscale, set saturation to 0
-// if (max === min) {
-// return {
-// hue: 0,
-// saturation: 0,
-// lightness: lightness * 100 // Convert to percentage
-// };
-// }
-// // Calculate the saturation
-// const d = max - min;
-// const saturation = lightness > 0.5 ? d / (2 - max - min) : d / (max + min);
-// // Calculate the hue
-// let hue;
-// if (max === normalizedR) {
-// hue = ((normalizedG - normalizedB) / d + (normalizedG < normalizedB ? 6 : 0)) * 60;
-// } else if (max === normalizedG) {
-// hue = ((normalizedB - normalizedR) / d + 2) * 60;
-// } else {
-// hue = ((normalizedR - normalizedG) / d + 4) * 60;
-// }
-// return {
-// hue: Math.round(hue),
-// saturation: Math.round(saturation * 100), // Convert to percentage
-// lightness: Math.round(lightness * 100) // Convert to percentage
-// };
-// }
-
-export function hexToHSL(hex) {
- var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
-
- var r = parseInt(result[1], 16);
- var g = parseInt(result[2], 16);
- var b = parseInt(result[3], 16);
-
- r /= 255, g /= 255, b /= 255;
- var max = Math.max(r, g, b), min = Math.min(r, g, b);
- var h, s, l = (max + min) / 2;
-
- if (max == min) {
- h = s = 0; // achromatic
- } else {
- var d = max - min;
- s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
- switch (max) {
- case r: h = (g - b) / d + (g < b ? 6 : 0); break;
- case g: h = (b - r) / d + 2; break;
- case b: h = (r - g) / d + 4; break;
- }
- h /= 6;
- }
-
- s = s * 100;
- s = Math.round(s);
- l = l * 100;
- l = Math.round(l);
- h = Math.round(360 * h);
-
- return {
- hue: h,
- saturation: s,
- lightness: l
- };
-}
diff --git a/.config/ags/modules/sideleft/tools/colorpicker.js b/.config/ags/modules/sideleft/tools/colorpicker.js
deleted file mode 100644
index cd37c6f03..000000000
--- a/.config/ags/modules/sideleft/tools/colorpicker.js
+++ /dev/null
@@ -1,283 +0,0 @@
-// TODO: Make selection update when entry changes
-const { Gtk } = imports.gi;
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Variable from 'resource:///com/github/Aylur/ags/variable.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { execAsync, exec } = Utils;
-const { Box, Button, Entry, EventBox, Icon, Label, Overlay, Scrollable } = Widget;
-import SidebarModule from './module.js';
-import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
-import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
-
-import { ColorPickerSelection, hslToHex, hslToRgbValues, hexToHSL } from './color.js';
-import { clamp } from '../../.miscutils/mathfuncs.js';
-
-export default () => {
- const selectedColor = new ColorPickerSelection();
- function shouldUseBlackColor() {
- return ((selectedColor.xAxis < 40 || (45 <= selectedColor.hue && selectedColor.hue <= 195)) &&
- selectedColor.yAxis > 60);
- }
- const colorBlack = 'rgba(0,0,0,0.9)';
- const colorWhite = 'rgba(255,255,255,0.9)';
- const hueRange = Box({
- homogeneous: true,
- className: 'sidebar-module-colorpicker-wrapper',
- children: [Box({
- className: 'sidebar-module-colorpicker-hue',
- css: `background: linear-gradient(to bottom, #ff6666, #ffff66, #66dd66, #66ffff, #6666ff, #ff66ff, #ff6666);`,
- })],
- });
- const hueSlider = Box({
- vpack: 'start',
- className: 'sidebar-module-colorpicker-cursorwrapper',
- css: `margin-top: ${13.636 * selectedColor.hue / 360}rem;`,
- homogeneous: true,
- children: [Box({
- className: 'sidebar-module-colorpicker-hue-cursor',
- })],
- setup: (self) => self.hook(selectedColor, () => {
- const widgetHeight = hueRange.children[0].get_allocated_height();
- self.setCss(`margin-top: ${13.636 * selectedColor.hue / 360}rem;`)
- }),
- });
- const hueSelector = Box({
- children: [EventBox({
- child: Overlay({
- child: hueRange,
- overlays: [hueSlider],
- }),
- attribute: {
- clicked: false,
- setHue: (self, event) => {
- const widgetHeight = hueRange.children[0].get_allocated_height();
- const [_, cursorX, cursorY] = event.get_coords();
- const cursorYPercent = clamp(cursorY / widgetHeight, 0, 1);
- selectedColor.hue = Math.round(cursorYPercent * 360);
- }
- },
- setup: (self) => self
- .on('motion-notify-event', (self, event) => {
- if (!self.attribute.clicked) return;
- self.attribute.setHue(self, event);
- })
- .on('button-press-event', (self, event) => {
- if (!(event.get_button()[1] === 1)) return; // We're only interested in left-click here
- self.attribute.clicked = true;
- self.attribute.setHue(self, event);
- })
- .on('button-release-event', (self) => self.attribute.clicked = false)
- ,
- })]
- });
- const saturationAndLightnessRange = Box({
- homogeneous: true,
- children: [Box({
- className: 'sidebar-module-colorpicker-saturationandlightness',
- attribute: {
- update: (self) => {
- // css: `background: linear-gradient(to right, #ffffff, color);`,
- self.setCss(`background:
- linear-gradient(to bottom, rgba(0,0,0,0), rgba(0,0,0,1)),
- linear-gradient(to right, #ffffff, ${hslToHex(selectedColor.hue, 100, 50)});
- `);
- },
- },
- setup: (self) => self
- .hook(selectedColor, self.attribute.update, 'hue')
- .hook(selectedColor, self.attribute.update, 'assigned')
- ,
- })],
- });
- const saturationAndLightnessCursor = Box({
- className: 'sidebar-module-colorpicker-saturationandlightness-cursorwrapper',
- children: [Box({
- vpack: 'start',
- hpack: 'start',
- homogeneous: true,
- css: `
- margin-left: ${13.636 * selectedColor.xAxis / 100}rem;
- margin-top: ${13.636 * (100 - selectedColor.yAxis) / 100}rem;
- `, // Why 13.636rem? see class name in stylesheet
- attribute: {
- update: (self) => {
- const allocation = saturationAndLightnessRange.children[0].get_allocation();
- self.setCss(`
- margin-left: ${13.636 * selectedColor.xAxis / 100}rem;
- margin-top: ${13.636 * (100 - selectedColor.yAxis) / 100}rem;
- `); // Why 13.636rem? see class name in stylesheet
- }
- },
- setup: (self) => self
- .hook(selectedColor, self.attribute.update, 'sl')
- .hook(selectedColor, self.attribute.update, 'assigned')
- ,
- children: [Box({
- className: 'sidebar-module-colorpicker-saturationandlightness-cursor',
- css: `
- background-color: ${hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))};
- border-color: ${shouldUseBlackColor() ? colorBlack : colorWhite};
- `,
- attribute: {
- update: (self) => {
- self.setCss(`
- background-color: ${hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))};
- border-color: ${shouldUseBlackColor() ? colorBlack : colorWhite};
- `);
- }
- },
- setup: (self) => self
- .hook(selectedColor, self.attribute.update, 'sl')
- .hook(selectedColor, self.attribute.update, 'hue')
- .hook(selectedColor, self.attribute.update, 'assigned')
- ,
- })],
- })]
- });
- const saturationAndLightnessSelector = Box({
- homogeneous: true,
- className: 'sidebar-module-colorpicker-saturationandlightness-wrapper',
- children: [EventBox({
- child: Overlay({
- child: saturationAndLightnessRange,
- overlays: [saturationAndLightnessCursor],
- }),
- attribute: {
- clicked: false,
- setSaturationAndLightness: (self, event) => {
- const allocation = saturationAndLightnessRange.children[0].get_allocation();
- const [_, cursorX, cursorY] = event.get_coords();
- const cursorXPercent = clamp(cursorX / allocation.width, 0, 1);
- const cursorYPercent = clamp(cursorY / allocation.height, 0, 1);
- selectedColor.xAxis = Math.round(cursorXPercent * 100);
- selectedColor.yAxis = Math.round(100 - cursorYPercent * 100);
- }
- },
- setup: (self) => self
- .on('motion-notify-event', (self, event) => {
- if (!self.attribute.clicked) return;
- self.attribute.setSaturationAndLightness(self, event);
- })
- .on('button-press-event', (self, event) => {
- if (!(event.get_button()[1] === 1)) return; // We're only interested in left-click here
- self.attribute.clicked = true;
- self.attribute.setSaturationAndLightness(self, event);
- })
- .on('button-release-event', (self) => self.attribute.clicked = false)
- ,
- })]
- });
- const resultColorBox = Box({
- className: 'sidebar-module-colorpicker-result-box',
- homogeneous: true,
- css: `background-color: ${hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))};`,
- children: [Label({
- className: 'txt txt-small',
- label: getString('Result'),
- }),],
- attribute: {
- update: (self) => {
- self.setCss(`background-color: ${hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))};`);
- self.children[0].setCss(`color: ${shouldUseBlackColor() ? colorBlack : colorWhite};`)
- }
- },
- setup: (self) => self
- .hook(selectedColor, self.attribute.update, 'sl')
- .hook(selectedColor, self.attribute.update, 'hue')
- .hook(selectedColor, self.attribute.update, 'assigned')
- ,
- });
- const ResultBox = ({ colorSystemName, updateCallback, copyCallback }) => Box({
- children: [
- Box({
- vertical: true,
- hexpand: true,
- children: [
- Label({
- xalign: 0,
- className: 'txt-tiny',
- label: colorSystemName,
- }),
- Overlay({
- child: Entry({
- widthChars: 10,
- className: 'txt-small techfont',
- attribute: {
- id: 0,
- update: updateCallback,
- },
- setup: (self) => self
- .hook(selectedColor, self.attribute.update, 'sl')
- .hook(selectedColor, self.attribute.update, 'hue')
- .hook(selectedColor, self.attribute.update, 'assigned')
- // .on('activate', (self) => {
- // const newColor = self.text;
- // if (newColor.length != 7) return;
- // selectedColor.setColorFromHex(self.text, self.attribute.id);
- // })
- ,
- }),
- })
- ]
- }),
- Button({
- child: MaterialIcon('content_copy', 'norm'),
- onClicked: (self) => {
- copyCallback(self);
- self.child.label = 'done';
- Utils.timeout(1000, () => self.child.label = 'content_copy');
- },
- setup: setupCursorHover,
- })
- ]
- });
- const resultHex = ResultBox({
- colorSystemName: 'Hex',
- updateCallback: (self, id) => {
- if (id && self.attribute.id === id) return;
- self.text = hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100));
- },
- copyCallback: () => Utils.execAsync(['wl-copy', `${hslToHex(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))}`]),
- })
- const resultRgb = ResultBox({
- colorSystemName: 'RGB',
- updateCallback: (self, id) => {
- if (id && self.attribute.id === id) return;
- self.text = hslToRgbValues(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100));
- },
- copyCallback: () => Utils.execAsync(['wl-copy', `rgb(${hslToRgbValues(selectedColor.hue, selectedColor.xAxis, selectedColor.yAxis / (1 + selectedColor.xAxis / 100))})`]),
- })
- const resultHsl = ResultBox({
- colorSystemName: 'HSL',
- updateCallback: (self, id) => {
- if (id && self.attribute.id === id) return;
- self.text = `${selectedColor.hue},${selectedColor.xAxis}%,${Math.round(selectedColor.yAxis / (1 + selectedColor.xAxis / 100))}%`;
- },
- copyCallback: () => Utils.execAsync(['wl-copy', `hsl(${selectedColor.hue},${selectedColor.xAxis}%,${Math.round(selectedColor.yAxis / (1 + selectedColor.xAxis / 100))}%)`]),
- })
- const result = Box({
- className: 'sidebar-module-colorpicker-result-area spacing-v-5 txt',
- hexpand: true,
- vertical: true,
- children: [
- resultColorBox,
- resultHex,
- resultRgb,
- resultHsl,
- ]
- })
- return SidebarModule({
- icon: MaterialIcon('colorize', 'norm'),
- name: getString('Color picker'),
- revealChild: false,
- child: Box({
- className: 'spacing-h-5',
- children: [
- hueSelector,
- saturationAndLightnessSelector,
- result,
- ]
- })
- });
-}
\ No newline at end of file
diff --git a/.config/ags/modules/sideleft/tools/conversions.js b/.config/ags/modules/sideleft/tools/conversions.js
deleted file mode 100644
index 8d26dc487..000000000
--- a/.config/ags/modules/sideleft/tools/conversions.js
+++ /dev/null
@@ -1,169 +0,0 @@
-const { Gtk } = imports.gi;
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { execAsync, exec } = Utils;
-const { Box, Button, Entry, EventBox, Icon, Label, Scrollable, Overlay } = Widget;
-import SidebarModule from './module.js';
-import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
-import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
-import { truncateToPrecision } from '../../.miscutils/mathfuncs.js';
-
-const VALUE_DEFAULT_PRECISION = 3;
-const conversions = [
- {
- unit1: 'px',
- unit2: 'rem',
- unit1Default: 5,
- formula1to2: '{{x}} / (parseFloat(Utils.exec(\'gsettings get org.gnome.desktop.interface font-name\').split(" ").pop().split("\'"))*4/3)',
- formula2to1: '{{x}} * (parseFloat(Utils.exec(\'gsettings get org.gnome.desktop.interface font-name\').split(" ").pop().split("\'"))*4/3)',
- forcePrecision: true,
- },
- {
- unit1: 'deg',
- unit2: 'rad',
- unit1Default: 90,
- formula1to2: '{{x}} * Math.PI / 180',
- formula2to1: '{{x}} * 180 / Math.PI',
- },
- {
- unit1: '°F',
- unit2: '°C',
- unit1Default: 68,
- formula1to2: '({{x}} - 32) * 5 / 9',
- formula2to1: '{{x}} * 9 / 5 + 32',
- },
- {
- unit1: 'Ft',
- unit2: 'Cm',
- formula1to2: '{{x}} * 30.48',
- formula2to1: '{{x}} / 30.48',
- },
- // {
- // unit1: 'Mile',
- // unit2: 'Km',
- // formula1to2: '{{x}} * 1.60934',
- // formula2to1: '{{x}} / 1.60934',
- // },
- // {
- // unit1: 'Inch',
- // unit2: 'Cm',
- // formula1to2: '{{x}} * 2.54',
- // formula2to1: '{{x}} / 2.54',
- // },
- {
- unit1: 'lbs',
- unit2: 'Kg',
- formula1to2: '{{x}} * 0.453592',
- formula2to1: '{{x}} / 0.453592',
- }
-]
-
-export default () => {
- const ValueBox = ({ unit, initValue = 0, updateCallback }) => {
- const unitName = Label({
- xalign: 0,
- className: 'txt txt-smallie txt-semibold margin-top-2 margin-left-2',
- label: `${unit}`,
- });
- const entry = Entry({
- hexpand: 'true',
- widthChars: 10,
- className: 'txt-small techfont margin-left-2',
- text: `${initValue}`,
- onChange: updateCallback,
- });
- const copyButton = Button({
- className: 'sidebar-module-csscalc-valuebox-copybtn',
- child: MaterialIcon('content_copy', 'norm'),
- onClicked: (self) => {
- Utils.execAsync(['wl-copy', entry.text]);
- self.child.label = 'done';
- Utils.timeout(1000, () => self.child.label = 'content_copy');
- },
- setup: setupCursorHover,
- });
- const wholeThing = Box({
- className: 'sidebar-module-csscalc-valuebox',
- vertical: true,
- hexpand: true,
- children: [
- unitName,
- Box({
- children: [
- entry,
- copyButton,
- ]
- })
- ],
- attribute: {
- updateValue: (value) => entry.text = `${value}`,
- getValue: () => entry.text,
- }
- });
- return wholeThing;
- }
- // Formula format is js expression, with `{{x}}` being the input value
- const BidirectionalConversion = ({
- unit1, unit2, unit1Default = 1,
- formula1to2, formula2to1,
- forcePrecision = false, precision = VALUE_DEFAULT_PRECISION,
- }) => {
- let updateLock = false;
- const convert = (value, formula) => {
- let thisValue;
- try {
- thisValue = eval(value)
- } catch (error) {
- thisValue = parseFloat(value);
- }
- // print(formula.replace('{{x}}', thisValue))
- // print(eval(formula.replace('{{x}}', thisValue)))
- const evalResult = eval(formula.replace('{{x}}', thisValue));
- const result = forcePrecision ?
- evalResult.toFixed(precision) : truncateToPrecision(evalResult, precision);
- // print(result)
- return result;
- }
- const unit1Box = ValueBox({
- unit: unit1,
- initValue: unit1Default,
- updateCallback: (self) => {
- if (updateLock) return;
- updateLock = true;
- const newValue = convert(self.text, formula1to2);
- unit2Box.attribute.updateValue(newValue || 0);
- updateLock = false;
- },
- });
- const unit2Box = ValueBox({
- unit: unit2,
- initValue: truncateToPrecision(eval(formula1to2.replace('\{{x}}', unit1Default)), precision),
- updateCallback: (self) => {
- if (updateLock) return;
- updateLock = true;
- const newValue = convert(self.text, formula2to1);
- unit1Box.attribute.updateValue(newValue || 0);
- updateLock = false;
- },
- });
- return Box({
- className: 'txt spacing-h-10',
- children: [
- unit1Box,
- MaterialIcon('swap_horiz', 'large'),
- unit2Box,
- ]
- })
- }
-
- return SidebarModule({
- icon: MaterialIcon('autorenew', 'norm'),
- name: getString('Conversions'),
- child: Box({
- vertical: true,
- className: 'spacing-v-5',
- children: conversions.map(BidirectionalConversion),
- })
- });
-}
\ No newline at end of file
diff --git a/.config/ags/modules/sideleft/tools/module.js b/.config/ags/modules/sideleft/tools/module.js
deleted file mode 100644
index 2cba49ec7..000000000
--- a/.config/ags/modules/sideleft/tools/module.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
-import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
-const { Box, Button, Icon, Label, Revealer } = Widget;
-
-export default ({
- icon,
- name,
- child,
- revealChild = true,
-}) => {
- const headerButtonIcon = MaterialIcon(revealChild ? 'expand_less' : 'expand_more', 'norm');
- const header = Button({
- onClicked: () => {
- content.revealChild = !content.revealChild;
- headerButtonIcon.label = content.revealChild ? 'expand_less' : 'expand_more';
- },
- setup: setupCursorHover,
- child: Box({
- className: 'txt spacing-h-10',
- children: [
- icon,
- Label({
- className: 'txt-norm',
- label: `${name}`,
- useMarkup: true,
- }),
- Box({
- hexpand: true,
- }),
- Box({
- className: 'sidebar-module-btn-arrow',
- homogeneous: true,
- children: [headerButtonIcon],
- })
- ]
- })
- });
- const content = Revealer({
- revealChild: revealChild,
- transition: 'slide_down',
- transitionDuration: userOptions.animations.durationLarge,
- child: Box({
- className: 'margin-top-5',
- homogeneous: true,
- children: [child],
- }),
- });
- return Box({
- className: 'sidebar-module',
- vertical: true,
- children: [
- header,
- content,
- ]
- });
-}
diff --git a/.config/ags/modules/sideleft/tools/name.js b/.config/ags/modules/sideleft/tools/name.js
deleted file mode 100644
index a5cca936e..000000000
--- a/.config/ags/modules/sideleft/tools/name.js
+++ /dev/null
@@ -1,26 +0,0 @@
-const { Gtk } = imports.gi;
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
-const { execAsync, exec } = Utils;
-const { Box, Button, CenterBox, EventBox, Icon, Label, Scrollable } = Widget;
-
-export default () => Box({
- className: 'txt sidebar-module techfont',
- children: [
- Label({
- label: getString('illogical-impulse')
- }),
- Box({ hexpand: true }),
- Button({
- className: 'sidebar-module-btn-arrow',
- onClicked: () => execAsync(['xdg-open', 'https://github.com/end-4/dots-hyprland']).catch(print),
- child: Icon({
- className: 'txt txt-norm',
- icon: 'github-symbolic',
- }),
- setup: setupCursorHover,
- })
- ]
-})
diff --git a/.config/ags/modules/sideleft/tools/quickscripts.js b/.config/ags/modules/sideleft/tools/quickscripts.js
deleted file mode 100644
index ccf0369e8..000000000
--- a/.config/ags/modules/sideleft/tools/quickscripts.js
+++ /dev/null
@@ -1,103 +0,0 @@
-const { Gtk } = imports.gi;
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { execAsync, exec } = Utils;
-const { Box, Button, EventBox, Icon, Label, Scrollable } = Widget;
-import SidebarModule from './module.js';
-import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
-import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
-
-import { distroID, isArchDistro, isDebianDistro, hasFlatpak } from '../../.miscutils/system.js';
-
-const scripts = [
- {
- icon: 'desktop-symbolic',
- name: getString('Change screen resolution'),
- command: `bash ${App.configDir}/modules/sideleft/tools/changeres.sh`,
- enabled: true,
- },
- {
- icon: 'nixos-symbolic',
- name: getString('Trim system generations to 5'),
- command: `sudo ${App.configDir}/scripts/quickscripts/nixos-trim-generations.sh 5 0 system`,
- enabled: distroID == 'nixos',
- },
- {
- icon: 'nixos-symbolic',
- name: getString('Trim home manager generations to 5'),
- command: `${App.configDir}/scripts/quickscripts/nixos-trim-generations.sh 5 0 home-manager`,
- enabled: distroID == 'nixos',
- },
- {
- icon: 'ubuntu-symbolic',
- name: getString('Update packages'),
- command: `sudo apt update && sudo apt upgrade -y`,
- enabled: isDebianDistro,
- },
- {
- icon: 'fedora-symbolic',
- name: getString('Update packages'),
- command: `sudo dnf upgrade -y`,
- enabled: distroID == 'fedora',
- },
- {
- icon: 'arch-symbolic',
- name: getString('Update packages'),
- command: `sudo pacman -Syyu`,
- enabled: isArchDistro,
- },
- {
- icon: 'arch-symbolic',
- name: getString('Remove orphan packages'),
- command: `sudo pacman -R (pacman -Qdtq)`,
- enabled: isArchDistro,
- },
- {
- icon: 'flatpak-symbolic',
- name: getString('Uninstall unused flatpak packages'),
- command: `flatpak uninstall --unused`,
- enabled: hasFlatpak,
- },
-];
-
-export default () => SidebarModule({
- icon: MaterialIcon('code', 'norm'),
- name: getString('Quick scripts'),
- child: Box({
- vertical: true,
- className: 'spacing-v-5',
- children: scripts.map((script) => {
- if (!script.enabled) return null;
- const scriptStateIcon = MaterialIcon('not_started', 'norm');
- return Box({
- className: 'spacing-h-5 txt',
- children: [
- Icon({
- className: 'sidebar-module-btn-icon txt-large',
- icon: script.icon,
- }),
- Label({
- className: 'txt-small',
- hpack: 'start',
- hexpand: true,
- label: script.name,
- tooltipText: script.command,
- }),
- Button({
- className: 'sidebar-module-scripts-button',
- child: scriptStateIcon,
- onClicked: () => {
- closeEverything();
- execAsync([`bash`, `-c`, `${userOptions.apps.terminal} fish -C "${script.command}"`]).catch(print)
- .then(() => {
- scriptStateIcon.label = 'done';
- })
- },
- setup: setupCursorHover,
- }),
- ],
- })
- }),
- })
-});
diff --git a/.config/ags/modules/sideright/calendar.js b/.config/ags/modules/sideright/calendar.js
deleted file mode 100644
index d70f98801..000000000
--- a/.config/ags/modules/sideright/calendar.js
+++ /dev/null
@@ -1,273 +0,0 @@
-import GLib from 'gi://GLib';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { Box, Button, Label, Overlay } = Widget;
-
-import { MaterialIcon } from '../.commonwidgets/materialicon.js';
-import { setupCursorHover } from '../.widgetutils/cursorhover.js';
-
-import Todo from "../../services/todo.js";
-import { TodoWidget } from "./todolist.js";
-import { getCalendarLayout } from "./calendar_layout.js";
-
-const AGS_CONFIG_FILE = `${App.configDir}/user_options.jsonc`;
-let calendarJson = getCalendarLayout(undefined, true);
-let monthshift = 0;
-
-function getDateInXMonthsTime(x) {
- var currentDate = new Date(); // Get the current date
- var targetMonth = currentDate.getMonth() + x; // Calculate the target month
- var targetYear = currentDate.getFullYear(); // Get the current year
-
- // Adjust the year and month if necessary
- targetYear += Math.floor(targetMonth / 12);
- targetMonth = (targetMonth % 12 + 12) % 12;
-
- // Create a new date object with the target year and month
- var targetDate = new Date(targetYear, targetMonth, 1);
-
- // Set the day to the last day of the month to get the desired date
- // targetDate.setDate(0);
-
- return targetDate;
-}
-
-const weekDays = [ // MONDAY IS THE FIRST DAY OF THE WEEK :HESRIGHTYOUKNOW:
- { day: getString('Mo'), today: 0 },
- { day: getString('Tu'), today: 0 },
- { day: getString('We'), today: 0 },
- { day: getString('Th'), today: 0 },
- { day: getString('Fr'), today: 0 },
- { day: getString('Sa'), today: 0 },
- { day: getString('Su'), today: 0 },
-]
-
-const CalendarDay = (day, today) => Widget.Button({
- className: `sidebar-calendar-btn ${today == 1 ? 'sidebar-calendar-btn-today' : (today == -1 ? 'sidebar-calendar-btn-othermonth' : '')}`,
- child: Widget.Overlay({
- child: Box({}),
- overlays: [Label({
- hpack: 'center',
- className: 'txt-smallie txt-semibold sidebar-calendar-btn-txt',
- label: String(day),
- })],
- })
-})
-
-const CalendarWidget = () => {
- const calendarMonthYear = Widget.Button({
- className: 'txt txt-large sidebar-calendar-monthyear-btn',
- onClicked: () => shiftCalendarXMonths(0),
- setup: (button) => {
- button.label = `${new Date().toLocaleString('default', { month: 'long' })} ${new Date().getFullYear()}`;
- setupCursorHover(button);
- }
- });
- const addCalendarChildren = (box, calendarJson) => {
- const children = box.get_children();
- for (let i = 0; i < children.length; i++) {
- const child = children[i];
- child.destroy();
- }
- box.children = calendarJson.map((row, i) => Widget.Box({
- className: 'spacing-h-5',
- children: row.map((day, i) => CalendarDay(day.day, day.today)),
- }))
- }
- function shiftCalendarXMonths(x) {
- if (x == 0) monthshift = 0;
- else monthshift += x;
- var newDate;
- if (monthshift == 0) newDate = new Date();
- else newDate = getDateInXMonthsTime(monthshift);
-
- calendarJson = getCalendarLayout(newDate, (monthshift == 0));
- calendarMonthYear.label = `${monthshift == 0 ? '' : '• '}${newDate.toLocaleString('default', { month: 'long' })} ${newDate.getFullYear()}`;
- addCalendarChildren(calendarDays, calendarJson);
- }
- const calendarHeader = Widget.Box({
- className: 'spacing-h-5 sidebar-calendar-header',
- setup: (box) => {
- box.pack_start(calendarMonthYear, false, false, 0);
- box.pack_end(Widget.Box({
- className: 'spacing-h-5',
- children: [
- Button({
- className: 'sidebar-calendar-monthshift-btn',
- onClicked: () => shiftCalendarXMonths(-1),
- child: MaterialIcon('chevron_left', 'norm'),
- setup: setupCursorHover,
- }),
- Button({
- className: 'sidebar-calendar-monthshift-btn',
- onClicked: () => shiftCalendarXMonths(1),
- child: MaterialIcon('chevron_right', 'norm'),
- setup: setupCursorHover,
- })
- ]
- }), false, false, 0);
- }
- })
- const calendarDays = Widget.Box({
- hexpand: true,
- vertical: true,
- className: 'spacing-v-5',
- setup: (box) => {
- addCalendarChildren(box, calendarJson);
- }
- });
- return Widget.EventBox({
- onScrollUp: () => shiftCalendarXMonths(-1),
- onScrollDown: () => shiftCalendarXMonths(1),
- child: Widget.Box({
- hpack: 'center',
- children: [
- Widget.Box({
- hexpand: true,
- vertical: true,
- className: 'spacing-v-5',
- children: [
- calendarHeader,
- Widget.Box({
- homogeneous: true,
- className: 'spacing-h-5',
- children: weekDays.map((day, i) => CalendarDay(day.day, day.today))
- }),
- calendarDays,
- ]
- })
- ]
- })
- });
-};
-
-export const ModuleCalendar = () => {
- const defaultShown = 'calendar';
- const navrailButton = (stackItemName, icon, name) => Widget.Button({
- className: 'button-minsize sidebar-navrail-btn txt-small spacing-h-5',
- onClicked: (button) => {
- contentStack.shown = stackItemName;
- const kids = button.get_parent().get_children();
- for (let i = 0; i < kids.length; i++) {
- if (kids[i] != button) kids[i].toggleClassName('sidebar-navrail-btn-active', false);
- else button.toggleClassName('sidebar-navrail-btn-active', true);
- }
- },
- child: Box({
- className: 'spacing-v-5',
- vertical: true,
- children: [
- Label({
- className: `txt icon-material txt-hugeass`,
- label: icon,
- }),
- Label({
- label: name,
- className: 'txt txt-smallie',
- }),
- ]
- }),
- setup: (button) => Utils.timeout(1, () => {
- setupCursorHover(button);
- button.toggleClassName('sidebar-navrail-btn-active', defaultShown === stackItemName);
- })
- });
- const navrail = Box({
- vpack: 'center',
- homogeneous: true,
- vertical: true,
- className: 'sidebar-navrail spacing-v-10',
- children: [
- navrailButton('calendar', 'calendar_month', getString('Calendar')),
- navrailButton('todo', 'done_outline', getString('To Do')),
- ]
- });
- const contentStack = Widget.Stack({
- hexpand: true,
- children: {
- 'calendar': CalendarWidget(),
- 'todo': TodoWidget(),
- },
- transition: 'slide_up_down',
- transitionDuration: userOptions.animations.durationLarge,
- setup: (stack) => Utils.timeout(1, () => {
- stack.shown = defaultShown;
- })
- })
-
- const CollapseButtonIcon = (collapse) => MaterialIcon(collapse ? 'expand_more' : 'expand_less', 'norm');
- const CollapseButton = (collapse) => {
- const collapseButtonIcon = CollapseButtonIcon(collapse);
- return Button({
- hpack: 'start',
- vpack: 'start',
- className: 'margin-top-5 margin-left-5 margin-bottom-5',
- onClicked: () => {
- mainStack.shown = (mainStack.shown == 'expanded') ? 'collapsed' : 'expanded';
- Utils.execAsync(['bash', '-c', `${App.configDir}/scripts/ags/agsconfigurator.py \
- --key "sidebar.calendar.expandByDefault" \
- --value ${!userOptions.sidebar.calendar.expandByDefault} \
- --file ${AGS_CONFIG_FILE}`
- ]).catch(print);
-
- },
- setup: setupCursorHover,
- child: Box({
- className: 'sidebar-calendar-btn-arrow txt',
- homogeneous: true,
- children: [collapseButtonIcon],
- }),
- tooltipText: collapse ? getString('Collapse calendar') : getString('Expand calendar'),
- })
- }
- const date = Variable('', {
- poll: [
- userOptions.time.interval,
- () => GLib.DateTime.new_now_local().format(userOptions.time.calendarDateFormat),
- ],
- })
-
- const collapsedWidget = Box({
- className: 'spacing-h-5',
- children: [
- CollapseButton(false),
- Widget.Label({
- vpack: 'center',
- className: 'txt txt-small sidebar-calendar-collapsed-pill',
- label: date.bind(),
- }),
- Widget.Label({
- vpack: 'center',
- className: 'txt txt-small sidebar-calendar-collapsed-pill',
- label: `${Todo.todo_json.length} ${getString('To do tasks')}`,
- setup: (self) => self.hook(Todo, (self) => {
- self.label = `${Todo.todo_json.length} ${getString('To do tasks')}`
- }, 'updated')
- }),
- ]
- })
-
- const mainStack = Widget.Stack({
- className: 'sidebar-group',
- homogeneous: false,
- children: {
- 'collapsed': collapsedWidget,
- 'expanded': Box({
- className: 'spacing-h-5',
- children: [
- Overlay({
- child: navrail,
- overlays: [CollapseButton(true)],
- }),
- contentStack
- ]
- }),
- },
- transition: 'slide_up_down',
- transitionDuration: userOptions.animations.durationLarge,
- shown: userOptions.sidebar.calendar.expandByDefault ? 'expanded' : 'collapsed',
- })
-
- return mainStack;
-}
-
diff --git a/.config/ags/modules/sideright/calendar_layout.js b/.config/ags/modules/sideright/calendar_layout.js
deleted file mode 100644
index 35b481d6d..000000000
--- a/.config/ags/modules/sideright/calendar_layout.js
+++ /dev/null
@@ -1,85 +0,0 @@
-function checkLeapYear(year) {
- return (
- year % 400 == 0 ||
- (year % 4 == 0 && year % 100 != 0));
-}
-
-function getMonthDays(month, year) {
- const leapYear = checkLeapYear(year);
- if ((month <= 7 && month % 2 == 1) || (month >= 8 && month % 2 == 0)) return 31;
- if (month == 2 && leapYear) return 29;
- if (month == 2 && !leapYear) return 28;
- return 30;
-}
-
-function getNextMonthDays(month, year) {
- const leapYear = checkLeapYear(year);
- if (month == 1 && leapYear) return 29;
- if (month == 1 && !leapYear) return 28;
- if (month == 12) return 31;
- if ((month <= 7 && month % 2 == 1) || (month >= 8 && month % 2 == 0)) return 30;
- return 31;
-}
-
-function getPrevMonthDays(month, year) {
- const leapYear = checkLeapYear(year);
- if (month == 3 && leapYear) return 29;
- if (month == 3 && !leapYear) return 28;
- if (month == 1) return 31;
- if ((month <= 7 && month % 2 == 1) || (month >= 8 && month % 2 == 0)) return 30;
- return 31;
-}
-
-export function getCalendarLayout(dateObject, highlight) {
- if (!dateObject) dateObject = new Date();
- const weekday = (dateObject.getDay() + 6) % 7; // MONDAY IS THE FIRST DAY OF THE WEEK
- const day = dateObject.getDate();
- const month = dateObject.getMonth() + 1;
- const year = dateObject.getFullYear();
- const weekdayOfMonthFirst = (weekday + 35 - (day - 1)) % 7;
- const daysInMonth = getMonthDays(month, year);
- const daysInNextMonth = getNextMonthDays(month, year);
- const daysInPrevMonth = getPrevMonthDays(month, year);
-
- // Fill
- var monthDiff = (weekdayOfMonthFirst == 0 ? 0 : -1);
- var toFill, dim;
- if(weekdayOfMonthFirst == 0) {
- toFill = 1;
- dim = daysInMonth;
- }
- else {
- toFill = (daysInPrevMonth - (weekdayOfMonthFirst - 1));
- dim = daysInPrevMonth;
- }
- var calendar = [...Array(6)].map(() => Array(7));
- var i = 0, j = 0;
- while (i < 6 && j < 7) {
- calendar[i][j] = {
- "day": toFill,
- "today": ((toFill == day && monthDiff == 0 && highlight) ? 1 : (
- monthDiff == 0 ? 0 :
- -1
- ))
- };
- // Increment
- toFill++;
- if (toFill > dim) { // Next month?
- monthDiff++;
- if (monthDiff == 0)
- dim = daysInMonth;
- else if (monthDiff == 1)
- dim = daysInNextMonth;
- toFill = 1;
- }
- // Next tile
- j++;
- if (j == 7) {
- j = 0;
- i++;
- }
-
- }
- return calendar;
-}
-
diff --git a/.config/ags/modules/sideright/centermodules/audiocontrols.js b/.config/ags/modules/sideright/centermodules/audiocontrols.js
deleted file mode 100644
index 7cc4ec354..000000000
--- a/.config/ags/modules/sideright/centermodules/audiocontrols.js
+++ /dev/null
@@ -1,222 +0,0 @@
-import Audio from 'resource:///com/github/Aylur/ags/service/audio.js';
-import Variable from 'resource:///com/github/Aylur/ags/variable.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-const { Box, Button, Icon, Label, Revealer, Scrollable, Slider, Stack } = Widget;
-import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
-import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
-import { iconExists, substitute } from '../../.miscutils/icons.js';
-
-const AppVolume = (stream) => Box({
- className: 'sidebar-volmixer-stream spacing-h-10',
- children: [
- Icon({
- className: 'sidebar-volmixer-stream-appicon',
- vpack: 'center',
- tooltipText: stream.stream.name,
- setup: (self) => {
- self.hook(stream, (self) => {
- self.icon = substitute(
- stream["icon-name"] ||
- stream.stream["icon-name"] ||
- stream.stream["application-id"] ||
- stream.stream["name"]);
- })
- },
- }),
- Box({
- hexpand: true,
- vpack: 'center',
- vertical: true,
- className: 'spacing-v-5',
- children: [
- Label({
- xalign: 0,
- maxWidthChars: 1,
- truncate: 'end',
- label: stream.description,
- className: 'txt-small',
- setup: (self) => self.hook(stream, (self) => {
- self.label = `${stream.stream.name} • ${stream.description}`
- })
- }),
- Slider({
- drawValue: false,
- hpack: 'fill',
- className: 'sidebar-volmixer-stream-slider',
- value: stream.volume,
- min: 0, max: 1,
- onChange: ({ value }) => {
- stream.volume = value;
- },
- setup: (self) => self.hook(stream, (self) => {
- self.value = stream.volume;
- self.adjustment["step-increment"] = 0.1;
- })
- }),
- // Box({
- // homogeneous: true,
- // className: 'test',
- // children: [AnimatedSlider({
- // className: 'sidebar-volmixer-stream-slider',
- // value: stream.volume,
- // })],
- // })
- ]
- })
- ]
-});
-
-const AudioDevices = (input = false) => {
- const dropdownShown = Variable(false);
- const DeviceStream = (stream) => Button({
- tooltipText: stream.description,
- child: Box({
- className: 'txt spacing-h-10',
- children: [
- iconExists(stream.iconName) ? Icon({
- className: 'txt-norm symbolic-icon',
- icon: stream.iconName,
- }) : MaterialIcon(input ? 'mic_external_on' : 'media_output', 'norm'),
- Label({
- hexpand: true,
- xalign: 0,
- className: 'txt-small',
- truncate: 'end',
- maxWidthChars: 1,
- label: stream.description,
- }),
- ],
- }),
- onClicked: (self) => {
- if (input) Audio.microphone = stream;
- else Audio.speaker = stream;
- dropdownShown.value = false;
- },
- setup: setupCursorHover,
- })
- const activeDevice = Button({
- onClicked: () => { dropdownShown.value = !dropdownShown.value; },
- child: Box({
- className: 'txt spacing-h-10',
- children: [
- MaterialIcon(input ? 'mic_external_on' : 'media_output', 'norm'),
- Label({
- hexpand: true,
- xalign: 0,
- className: 'txt-small',
- truncate: 'end',
- maxWidthChars: 1,
- label: `${input ? '[In]' : '[Out]'}`,
- setup: (self) => self.hook(Audio, (self) => {
- self.label = `${input ? '[In]' : '[Out]'} ${input ? Audio.microphone.description : Audio.speaker.description}`;
- })
- }),
- Label({
- className: `icon-material txt-norm`,
- setup: (self) => self.hook(dropdownShown, (self) => {
- self.label = dropdownShown.value ? 'expand_less' : 'expand_more';
- })
- })
- ],
- }),
- setup: setupCursorHover,
- });
- const deviceSelector = Revealer({
- transition: 'slide_down',
- revealChild: dropdownShown.bind("value"),
- transitionDuration: userOptions.animations.durationSmall,
- child: Box({
- vertical: true,
- children: [
- Box({ className: 'separator-line margin-top-5 margin-bottom-5' }),
- Box({
- vertical: true,
- className: 'spacing-v-5 margin-top-5',
- attribute: {
- 'updateStreams': (self) => {
- const streams = input ? Audio.microphones : Audio.speakers;
- self.children = streams.map(stream => DeviceStream(stream));
- },
- },
- setup: (self) => self
- .hook(Audio, self.attribute.updateStreams, 'stream-added')
- .hook(Audio, self.attribute.updateStreams, 'stream-removed')
- ,
- }),
- ]
- })
- })
- return Box({
- hpack: 'fill',
- className: 'sidebar-volmixer-deviceselector',
- vertical: true,
- children: [
- activeDevice,
- deviceSelector,
- ]
- })
-}
-
-export default (props) => {
- const emptyContent = Box({
- homogeneous: true,
- children: [Box({
- vertical: true,
- vpack: 'center',
- className: 'txt spacing-v-10',
- children: [
- Box({
- vertical: true,
- className: 'spacing-v-5 txt-subtext',
- children: [
- MaterialIcon('brand_awareness', 'gigantic'),
- Label({ label: getString('No audio source'), className: 'txt-small' }),
- ]
- }),
- ]
- })]
- });
- const appList = Scrollable({
- vexpand: true,
- child: Box({
- attribute: {
- 'updateStreams': (self) => {
- const streams = Audio.apps;
- self.children = streams.map(stream => AppVolume(stream));
- },
- },
- vertical: true,
- className: 'spacing-v-5',
- setup: (self) => self
- .hook(Audio, self.attribute.updateStreams, 'stream-added')
- .hook(Audio, self.attribute.updateStreams, 'stream-removed')
- ,
- })
- })
- const devices = Box({
- vertical: true,
- className: 'spacing-v-5',
- children: [
- AudioDevices(false),
- AudioDevices(true),
- ]
- })
- const mainContent = Stack({
- children: {
- 'empty': emptyContent,
- 'list': appList,
- },
- setup: (self) => self.hook(Audio, (self) => {
- self.shown = (Audio.apps.length > 0 ? 'list' : 'empty')
- }),
- })
- return Box({
- ...props,
- className: 'spacing-v-5',
- vertical: true,
- children: [
- mainContent,
- devices,
- ]
- });
-}
diff --git a/.config/ags/modules/sideright/centermodules/bluetooth.js b/.config/ags/modules/sideright/centermodules/bluetooth.js
deleted file mode 100644
index 86648be28..000000000
--- a/.config/ags/modules/sideright/centermodules/bluetooth.js
+++ /dev/null
@@ -1,164 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import Bluetooth from 'resource:///com/github/Aylur/ags/service/bluetooth.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { Box, Button, Icon, Label, Scrollable, Slider, Stack, Overlay } = Widget;
-const { execAsync, exec } = Utils;
-import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
-import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
-import { ConfigToggle } from '../../.commonwidgets/configwidgets.js';
-
-// can't connect: sync_problem
-
-const USE_SYMBOLIC_ICONS = true;
-
-const BluetoothDevice = (device) => {
- // console.log(device);
- const deviceIcon = Icon({
- className: 'sidebar-bluetooth-appicon',
- vpack: 'center',
- tooltipText: device.name,
- setup: (self) => self.hook(device, (self) => {
- self.icon = `${device.iconName}${USE_SYMBOLIC_ICONS ? '-symbolic' : ''}`;
- }),
- });
- const deviceStatus = Box({
- hexpand: true,
- vpack: 'center',
- vertical: true,
- children: [
- Label({
- xalign: 0,
- maxWidthChars: 1,
- truncate: 'end',
- label: device.name,
- className: 'txt-small',
- setup: (self) => self.hook(device, (self) => {
- self.label = device.name;
- }),
- }),
- Label({
- xalign: 0,
- maxWidthChars: 1,
- truncate: 'end',
- label: device.connected ? 'Connected' : (device.paired ? 'Paired' : ''),
- className: 'txt-subtext',
- setup: (self) => self.hook(device, (self) => {
- self.label = device.connected ? getString('Connected') : (device.paired ? getString('Paired') : '');
- }),
- }),
- ]
- });
- const deviceConnectButton = ConfigToggle({
- vpack: 'center',
- expandWidget: false,
- desc: 'Toggle connection',
- initValue: device.connected,
- onChange: (self, newValue) => {
- device.setConnection(newValue);
- },
- extraSetup: (self) => {
- self.hook(device, () => {
- const enabledState = self.attribute.enabled;
- if (enabledState.value !== device.connected)
- enabledState.value = device.connected;
- });
- },
- })
- const deviceRemoveButton = Button({
- vpack: 'center',
- className: 'sidebar-bluetooth-device-remove',
- child: MaterialIcon('delete', 'norm'),
- tooltipText: getString('Remove device'),
- setup: setupCursorHover,
- onClicked: () => execAsync(['bluetoothctl', 'remove', device.address]).catch(print),
- });
- return Box({
- className: 'sidebar-bluetooth-device spacing-h-10',
- children: [
- deviceIcon,
- deviceStatus,
- Box({
- className: 'spacing-h-5',
- children: [
- deviceConnectButton,
- deviceRemoveButton,
- ]
- })
- ]
- })
-}
-
-export default (props) => {
- const emptyContent = Box({
- homogeneous: true,
- children: [Box({
- vertical: true,
- vpack: 'center',
- className: 'txt spacing-v-10',
- children: [
- Box({
- vertical: true,
- className: 'spacing-v-5 txt-subtext',
- children: [
- MaterialIcon('bluetooth_disabled', 'gigantic'),
- Label({ label: 'No Bluetooth devices', className: 'txt-small' }),
- ]
- }),
- ]
- })]
- });
- const deviceList = Overlay({
- passThrough: true,
- child: Scrollable({
- vexpand: true,
- child: Box({
- attribute: {
- 'updateDevices': (self) => {
- const devices = Bluetooth.devices;
- self.children = devices.map(d => BluetoothDevice(d));
- },
- },
- vertical: true,
- className: 'spacing-v-5 margin-bottom-15',
- setup: (self) => self
- .hook(Bluetooth, self.attribute.updateDevices, 'device-added')
- .hook(Bluetooth, self.attribute.updateDevices, 'device-removed')
- ,
- })
- }),
- overlays: [Box({
- className: 'sidebar-centermodules-scrollgradient-bottom'
- })]
- });
- const mainContent = Stack({
- children: {
- 'empty': emptyContent,
- 'list': deviceList,
- },
- setup: (self) => self.hook(Bluetooth, (self) => {
- self.shown = (Bluetooth.devices.length > 0 ? 'list' : 'empty')
- }),
- })
- const bottomBar = Box({
- homogeneous: true,
- children: [Button({
- hpack: 'center',
- className: 'txt-small txt sidebar-centermodules-bottombar-button',
- onClicked: () => {
- execAsync(['bash', '-c', userOptions.apps.bluetooth]).catch(print);
- closeEverything();
- },
- label: getString('More'),
- setup: setupCursorHover,
- })],
- })
- return Box({
- ...props,
- className: 'spacing-v-5',
- vertical: true,
- children: [
- mainContent,
- bottomBar
- ]
- });
-}
diff --git a/.config/ags/modules/sideright/centermodules/configure.js b/.config/ags/modules/sideright/centermodules/configure.js
deleted file mode 100644
index 572c77c21..000000000
--- a/.config/ags/modules/sideright/centermodules/configure.js
+++ /dev/null
@@ -1,104 +0,0 @@
-const { GLib } = imports.gi;
-import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { Box, Button, Icon, Label, Scrollable, Slider, Stack, Overlay } = Widget;
-const { execAsync, exec } = Utils;
-import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
-import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
-import { ConfigGap, ConfigToggle } from '../../.commonwidgets/configwidgets.js';
-import { AgsSpinButton, HyprlandSpinButton, HyprlandToggle } from '../../.commonwidgets/configwidgets_apps.js';
-
-const Subcategory = (children) => Box({
- className: 'margin-left-20',
- vertical: true,
- children: children,
-})
-
-export default (props) => {
- const ConfigSection = ({ name, children }) => Box({
- vertical: true,
- className: 'spacing-v-5',
- children: [
- Label({
- hpack: 'center',
- className: 'txt txt-large margin-left-10',
- label: name,
- }),
- Box({
- className: 'margin-left-10 margin-right-10',
- vertical: true,
- children: children,
- })
- ]
- })
- const mainContent = Overlay({
- passThrough: true,
- child: Scrollable({
- vexpand: true,
- child: Box({
- vertical: true,
- className: 'spacing-v-10 sidebar-centermodules-scrollgradient-bottom-contentmargin',
- children: [
- ConfigSection({
- name: getString('Effects'), children: [
- ConfigToggle({
- icon: 'border_clear',
- name: getString('Transparency'),
- desc: getString('[AGS]\nMake shell elements transparent\nBlur is also recommended if you enable this'),
- initValue: exec(`bash -c "sed -n \'2p\' ${GLib.get_user_state_dir()}/ags/user/colormode.txt"`) == "transparent",
- onChange: (self, newValue) => {
- const transparency = newValue == 0 ? "opaque" : "transparent";
- console.log(transparency);
- execAsync([`bash`, `-c`, `mkdir -p ${GLib.get_user_state_dir()}/ags/user && sed -i "2s/.*/${transparency}/" ${GLib.get_user_state_dir()}/ags/user/colormode.txt`])
- .then(execAsync(['bash', '-c', `${App.configDir}/scripts/color_generation/switchcolor.sh`]))
- .catch(print);
- },
- }),
- HyprlandToggle({ icon: 'blur_on', name: getString('Blur'), desc: getString("[Hyprland]\nEnable blur on transparent elements\nDoesn't affect performance/power consumption unless you have transparent windows."), option: "decoration:blur:enabled" }),
- Subcategory([
- HyprlandToggle({ icon: 'stack_off', name: getString('X-ray'), desc: getString("[Hyprland]\nMake everything behind a window/layer except the wallpaper not rendered on its blurred surface\nRecommended to improve performance (if you don't abuse transparency/blur) "), option: "decoration:blur:xray" }),
- HyprlandSpinButton({ icon: 'target', name: getString('Size'), desc: getString('[Hyprland]\nAdjust the blur radius. Generally doesn\'t affect performance\nHigher = more color spread'), option: 'decoration:blur:size', minValue: 1, maxValue: 1000 }),
- HyprlandSpinButton({ icon: 'repeat', name: getString('Passes'), desc: getString('[Hyprland] Adjust the number of runs of the blur algorithm\nMore passes = more spread and power consumption\n4 is recommended\n2- would look weird and 6+ would look lame.'), option: 'decoration:blur:passes', minValue: 1, maxValue: 10 }),
- ]),
- ConfigGap({}),
- HyprlandToggle({
- icon: 'animation', name: getString('Animations'), desc: getString('[Hyprland] [GTK]\nEnable animations'), option: 'animations:enabled',
- extraOnChange: (self, newValue) => execAsync(['gsettings', 'set', 'org.gnome.desktop.interface', 'enable-animations', `${newValue}`]),
- extraOnReset: (self, newValue) => execAsync(['gsettings', 'set', 'org.gnome.desktop.interface', 'enable-animations', 'true']),
- }),
- Subcategory([
- AgsSpinButton({
- option: "animations.choreographyDelay",
- icon: 'clear_all',
- name: getString('Choreography delay'),
- desc: getString('In milliseconds, the delay between animations of a series'),
- step: 10, minValue: 0, maxValue: 1000,
- })
- ]),
- ]
- }),
- ConfigSection({
- name: getString('Developer'), children: [
- HyprlandToggle({ icon: 'speed', name: getString('Show FPS'), desc: getString("[Hyprland]\nShow FPS overlay on top-left corner"), option: "debug:overlay", save: false }),
- HyprlandToggle({ icon: 'sort', name: getString('Log to stdout'), desc: getString("[Hyprland]\nPrint LOG, ERR, WARN, etc. messages to the console"), option: "debug:enable_stdout_logs" }),
- HyprlandToggle({ icon: 'motion_sensor_active', name: getString('Damage tracking'), desc: getString("[Hyprland]\nEnable damage tracking\nGenerally, leave it on.\nTurn off only when a shader doesn't work"), option: "debug:damage_tracking", enableValue: 2, save: false }),
- HyprlandToggle({ icon: 'destruction', name: getString('Damage blink'), desc: getString("[Hyprland] [Epilepsy warning!]\nShow screen damage flashes"), option: "debug:damage_blink", save: false }),
- ]
- }),
- ]
- })
- }),
- overlays: [Box({
- className: 'sidebar-centermodules-scrollgradient-bottom'
- })]
- });
- return Box({
- ...props,
- className: 'spacing-v-5',
- vertical: true,
- children: [
- mainContent,
- ]
- });
-}
diff --git a/.config/ags/modules/sideright/centermodules/notificationlist.js b/.config/ags/modules/sideright/centermodules/notificationlist.js
deleted file mode 100644
index 48e94a24b..000000000
--- a/.config/ags/modules/sideright/centermodules/notificationlist.js
+++ /dev/null
@@ -1,181 +0,0 @@
-// This file is for the notification list on the sidebar
-// For the popup notifications, see onscreendisplay.js
-// The actual widget for each single notification is in ags/modules/.commonwidgets/notification.js
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
-const { Box, Button, Label, Revealer, Scrollable, Stack } = Widget;
-import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
-import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
-import Notification from '../../.commonwidgets/notification.js';
-import { ConfigToggle } from '../../.commonwidgets/configwidgets.js';
-
-export default (props) => {
- let previousLength;
- let clearing = false;
-
- const notifEmptyContent = Box({
- homogeneous: true,
- children: [Box({
- vertical: true,
- vpack: 'center',
- className: 'txt spacing-v-10',
- children: [
- Box({
- vertical: true,
- className: 'spacing-v-5 txt-subtext',
- children: [
- MaterialIcon('notifications_active', 'gigantic'),
- Label({ label: getString('No notifications'), className: 'txt-small' }),
- ]
- }),
- ]
- })]
- });
- const notificationList = Box({
- vertical: true,
- vpack: 'start',
- className: 'spacing-v-5-revealer',
- setup: (self) => self
- .hook(Notifications, (box, id) => {
- if (box.get_children().length == 0) { // On init there's no notif, or 1st notif
- Notifications.notifications
- .forEach(n => {
- box.pack_end(Notification({
- notifObject: n,
- isPopup: false,
- }), false, false, 0)
- });
- box.show_all();
- return;
- }
- // 2nd or later notif
- const notif = Notifications.getNotification(id);
- const NewNotif = Notification({
- notifObject: notif,
- isPopup: false,
- });
- if (NewNotif) {
- box.pack_end(NewNotif, false, false, 0);
- box.show_all();
- }
- }, 'notified')
- .hook(Notifications, (box, id) => {
- if (!id) return;
- for (const ch of box.children) {
- if (ch._id === id) {
- ch.attribute.destroyWithAnims();
- }
- }
- }, 'closed')
- ,
- });
- const ListActionButton = (icon, name, action) => Button({
- className: 'sidebar-centermodules-bottombar-button',
- onClicked: action,
- child: Box({
- hpack: 'center',
- className: 'spacing-h-5',
- children: [
- MaterialIcon(icon, 'norm'),
- Label({
- className: 'txt-small',
- label: name,
- })
- ]
- }),
- setup: setupCursorHover,
- });
- const silenceButton = ListActionButton('notifications_paused', getString('Silence'), (self) => {
- Notifications.dnd = !Notifications.dnd;
- self.toggleClassName('notif-listaction-btn-enabled', Notifications.dnd);
- });
- const clearButton = Revealer({
- transition: 'slide_right',
- transitionDuration: userOptions.animations.durationSmall,
- setup: (self) => self.hook(Notifications, (self) => {
- self.revealChild = Notifications.notifications.length > 0;
- }),
- child: ListActionButton('clear_all', getString('Clear'), () => {
- clearing = true;
- Notifications.clear();
- const kids = notificationList.get_children();
- for (let i = 0; i < kids.length; i++) {
- const kid = kids[i];
- Utils.timeout(userOptions.animations.choreographyDelay * i, () => kid.attribute.destroyWithAnims());
- }
- })
- })
- const notifCount = Label({
- attribute: {
- updateCount: (self) => {
- const count = Notifications.notifications.length;
- if (count > 0) self.label = `${count} ${getString("notifications")}`;
- else self.label = '';
- },
- },
- hexpand: true,
- xalign: 0,
- className: 'txt-small margin-left-10',
- label: `${Notifications.notifications.length}`,
- setup: (self) => self
- .hook(Notifications, (box, id) => self.attribute.updateCount(self), 'notified')
- .hook(Notifications, (box, id) => self.attribute.updateCount(self), 'dismissed')
- .hook(Notifications, (box, id) => self.attribute.updateCount(self), 'closed')
- ,
- });
- const listTitle = Box({
- vpack: 'start',
- className: 'txt spacing-h-5',
- children: [
- notifCount,
- silenceButton,
- clearButton,
- ]
- });
- const notifList = Scrollable({
- hexpand: true,
- hscroll: 'never',
- vscroll: 'automatic',
- child: Box({
- vexpand: true,
- homogeneous: true,
- children: [notificationList],
- }),
- setup: (self) => {
- const vScrollbar = self.get_vscrollbar();
- vScrollbar.get_style_context().add_class('sidebar-scrollbar');
- }
- });
- const listContents = Stack({
- transition: 'crossfade',
- transitionDuration: userOptions.animations.durationLarge,
- children: {
- 'empty': notifEmptyContent,
- 'list': notifList,
- },
- setup: (self) => {
- previousLength = Notifications.notifications.length;
- self.hook(Notifications, (self) => {
- if (Notifications.notifications.length > 0) {
- self.shown = 'list';
- if (!clearing) previousLength = Notifications.notifications.length;
- }
- else {
- Utils.timeout(userOptions.animations.choreographyDelay * previousLength, () => {
- clearing = false;
- if (Notifications.notifications.length == 0) self.shown = 'empty';
- })
- }
- })
- },
- });
- return Box({
- ...props,
- className: 'spacing-v-5',
- vertical: true,
- children: [
- listContents,
- listTitle,
- ]
- });
-}
diff --git a/.config/ags/modules/sideright/centermodules/wifinetworks.js b/.config/ags/modules/sideright/centermodules/wifinetworks.js
deleted file mode 100644
index bac78f881..000000000
--- a/.config/ags/modules/sideright/centermodules/wifinetworks.js
+++ /dev/null
@@ -1,421 +0,0 @@
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Network from "resource:///com/github/Aylur/ags/service/network.js";
-import Variable from 'resource:///com/github/Aylur/ags/variable.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { Box, Button, Entry, Icon, Label, Revealer, Scrollable, Slider, Stack, Overlay } = Widget;
-const { execAsync, exec } = Utils;
-import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
-import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
-import { ConfigToggle } from '../../.commonwidgets/configwidgets.js';
-
-const MATERIAL_SYMBOL_SIGNAL_STRENGTH = {
- 'network-wireless-signal-excellent-symbolic': "signal_wifi_4_bar",
- 'network-wireless-signal-good-symbolic': "network_wifi_3_bar",
- 'network-wireless-signal-ok-symbolic': "network_wifi_2_bar",
- 'network-wireless-signal-weak-symbolic': "network_wifi_1_bar",
- 'network-wireless-signal-none-symbolic': "signal_wifi_0_bar",
-}
-
-let connectAttempt = '';
-let networkAuth = null;
-let networkAuthSSID = null;
-
-const WifiNetwork = (accessPoint) => {
- const networkStrength = MaterialIcon(MATERIAL_SYMBOL_SIGNAL_STRENGTH[accessPoint.iconName], 'hugerass')
- const networkName = Box({
- vertical: true,
- children: [
- Label({
- hpack: 'start',
- label: accessPoint.ssid
- }),
- accessPoint.active ? Label({
- hpack: 'start',
- className: 'txt-smaller txt-subtext',
- label: getString("Selected"),
- }) : null,
- ]
- });
- return Button({
- onClicked: accessPoint.active ? () => { } : () => {
- connectAttempt = accessPoint.ssid;
- networkAuthSSID.label = `${getString('Connecting to')}: ${connectAttempt}`;
-
- // Check if the SSID is stored
- execAsync(['nmcli', '-g', 'NAME', 'connection', 'show'])
- .then((savedConnections) => {
- const savedSSIDs = savedConnections.split('\n');
-
- if (!savedSSIDs.includes(connectAttempt)) { // SSID not saved: show password input
- if (networkAuth) {
- networkAuth.revealChild = true;
- }
- } else { // If SSID is saved, hide password input
- if (networkAuth) {
- networkAuth.revealChild = false;
- }
- // Connect
- execAsync(['nmcli', 'device', 'wifi', 'connect', connectAttempt])
- .catch(print);
- }
- })
- .catch(print);
-
- },
- child: Box({
- className: 'sidebar-wifinetworks-network spacing-h-10',
- children: [
- networkStrength,
- networkName,
- Box({ hexpand: true }),
- accessPoint.active ? MaterialIcon('check', 'large') : null,
- ],
- }),
- setup: accessPoint.active ? () => { } : setupCursorHover,
- })
-}
-
-const NetResource = (icon, command) => {
- const resourceLabel = Label({
- className: `txt-smaller txt-subtext`,
- });
- const widget = Button({
- child: Box({
- hpack: 'start',
- className: `spacing-h-4`,
- children: [
- MaterialIcon(icon, 'very-small'),
- resourceLabel,
- ],
- setup: (self) => self.poll(2000, () => execAsync(['bash', '-c', command])
- .then((output) => {
- resourceLabel.label = output;
- }).catch(print))
- ,
- })
- });
- return widget;
-}
-
-const CurrentNetwork = () => {
- const passwordVisible = Variable(false);
- let authLock = false;
- let timeoutId = null;
-
- const bottomSeparator = Box({
- className: 'separator-line',
- });
- const networkName = Box({
- vertical: true,
- hexpand: true,
- children: [
- Label({
- hpack: 'start',
- className: 'txt-smaller txt-subtext',
- label: getString("Current network"),
- }),
- Label({
- hpack: 'start',
- label: Network.wifi?.ssid,
- setup: (self) => self.hook(Network, (self) => {
- if (authLock) return;
- self.label = Network.wifi?.ssid;
- }),
- }),
- ]
- });
- const networkBandwidth = Box({
- vertical: true,
- hexpand: true,
- hpack: 'end',
- className: 'sidebar-wifinetworks-bandwidth',
- children: [
- NetResource('arrow_warm_up', `${App.configDir}/scripts/network_scripts/network_bandwidth.py sent`),
- NetResource('arrow_cool_down', `${App.configDir}/scripts/network_scripts/network_bandwidth.py recv`),
- ]
- });
- // const networkStatus = Box({
- // children: [Label({
- // vpack: 'center',
- // className: 'txt-subtext',
- // setup: (self) => self.hook(Network, (self) => {
- // if (authLock) return;
- // self.label = Network.wifi.state;
- // }),
- // })]
- // });
- networkAuthSSID = Label({
- className: 'margin-left-5',
- hpack: 'start',
- hexpand: true,
- label: '',
- });
- const cancelAuthButton = Button({
- className: 'txt sidebar-wifinetworks-network-button',
- label: getString('Cancel'),
- hpack: 'end',
- onClicked: () => {
- passwordVisible.value = false;
- networkAuth.revealChild = false;
- authFailed.revealChild = false;
- networkAuthSSID.label = '';
- networkName.children[1].label = Network.wifi?.ssid;
- authEntry.text = '';
- },
- setup: setupCursorHover,
- });
- const authHeader = Box({
- vertical: false,
- hpack: 'fill',
- spacing: 10,
- children: [
- networkAuthSSID,
- cancelAuthButton
- ]
- });
- const authVisible = Button({
- vpack: 'center',
- child: MaterialIcon('visibility', 'large'),
- className: 'txt sidebar-wifinetworks-auth-visible',
- onClicked: (self) => {
- passwordVisible.value = !passwordVisible.value;
- },
- setup: (self) => {
- setupCursorHover(self)
- self.hook(passwordVisible, (self) => {
- self.child.label = passwordVisible.value ? 'visibility_off' : 'visibility';
- })
- },
- });
- const authFailed = Revealer({
- revealChild: false,
- child: Label({
- className: 'txt txt-italic txt-subtext',
- label: getString('Authentication failed'),
- }),
- })
- const authEntry = Entry({
- className: 'sidebar-wifinetworks-auth-entry',
- visibility: false,
- hexpand: true,
- onAccept: (self) => {
- authLock = false;
- // Delete SSID connection before attempting to reconnect
- execAsync(['nmcli', 'connection', 'delete', connectAttempt])
- .catch(() => { }); // Ignore error if SSID not found
-
- execAsync(['nmcli', 'device', 'wifi', 'connect', connectAttempt, 'password', self.text])
- .then(() => {
- connectAttempt = ''; // Reset SSID after successful connection
- networkAuth.revealChild = false; // Hide input if successful
- authFailed.revealChild = false; // Hide failed message if successful
- self.text = ''; // Empty input for retry
- passwordVisible.value = false;
- })
- .catch(() => {
- // Connection failed, show password input again
- networkAuth.revealChild = true;
- authFailed.revealChild = true;
- });
- },
- setup: (self) => self.hook(passwordVisible, (self) => {
- self.visibility = passwordVisible.value
- }),
- placeholderText: getString('Enter network password'),
- });
- const authBox = Box({
- className: 'sidebar-wifinetworks-auth-box',
- children: [
- authEntry,
- authVisible,
- ]
- });
- const forgetButton = Button({
- label: getString('Forget'),
- hexpand: true,
- className: 'txt sidebar-wifinetworks-network-button',
- onClicked: () => {
- execAsync(['nmcli', '-t', '-f', 'ACTIVE,NAME', 'connection', 'show'])
- .then(output => {
- const activeSSID = output
- .split('\n')
- .find(line => line.startsWith('yes:'))
- ?.split(':')[1];
-
- if (activeSSID) {
- execAsync(['nmcli', 'connection', 'delete', activeSSID])
- .catch(err => Utils.execAsync(['notify-send',
- "Network",
- `Failed to forget network - Hold to copy\n${err}`,
- '-a', 'ags',
- ]).catch(print));
- }
- })
- .catch();
- },
- setup: setupCursorHover,
- });
- const propertiesButton = Button({
- label: getString('Properties'),
- className: 'txt sidebar-wifinetworks-network-button',
- hexpand: true,
- onClicked: () => {
- Utils.execAsync('nmcli -t -f uuid connection show --active').then(uuid => {
- if (uuid.trim()) {
- Utils.execAsync(`nm-connection-editor --edit ${uuid.trim()}`);
- }
- closeEverything();
- }).catch(err => Utils.execAsync(['notify-send',
- "Network",
- `Failed to get connection UUID - Hold to copy\n${err}`,
- '-a', 'ags',
- ]).catch(print));
- },
- setup: setupCursorHover,
- });
- const networkProp = Revealer({
- transition: 'slide_down',
- transitionDuration: userOptions.animations.durationLarge,
- child: Box({
- className: 'spacing-h-10',
- homogeneous: true,
- children: [
- propertiesButton,
- forgetButton,
- ],
- setup: setupCursorHover,
- }),
- setup: (self) => self.hook(Network, (self) => {
- if (Network.wifi?.ssid === '') self.revealChild = false;
- else self.revealChild = true;
- }),
- });
- networkAuth = Revealer({
- transition: 'slide_down',
- transitionDuration: userOptions.animations.durationLarge,
- child: Box({
- className: 'margin-top-10 spacing-v-5',
- vertical: true,
- children: [
- authHeader,
- authBox,
- authFailed,
- ]
- }),
- setup: (self) => self.hook(Network, (self) => {
- execAsync(['nmcli', '-g', 'NAME', 'connection', 'show'])
- .then((savedConnections) => {
- const savedSSIDs = savedConnections.split('\n');
- if (Network.wifi.state == 'failed' ||
- (Network.wifi.state == 'need_auth' && !savedSSIDs.includes(Network.wifi.ssid))) {
- authLock = true;
- connectAttempt = Network.wifi.ssid;
- self.revealChild = true;
- if (timeoutId) {
- clearTimeout(timeoutId);
- }
- timeoutId = setTimeout(() => {
- authLock = false;
- passwordVisible.value = false;
- self.revealChild = false;
- authFailed.revealChild = false;
- Network.wifi.state = 'activated';
- }, 60000); // 60 seconds timeout
- }
- }
- ).catch(print);
- }),
- });
- const actualContent = Box({
- vertical: true,
- className: 'spacing-v-10',
- children: [
- Box({
- className: 'sidebar-wifinetworks-network',
- vertical: true,
- children: [
- Box({
- className: 'spacing-h-10 margin-bottom-10',
- children: [
- MaterialIcon('language', 'hugerass'),
- networkName,
- networkBandwidth,
- // networkStatus,
- ]
- }),
- networkProp,
- networkAuth
- ]
- }),
- bottomSeparator,
- ]
- });
- return Box({
- vertical: true,
- children: [Revealer({
- transition: 'slide_down',
- transitionDuration: userOptions.animations.durationLarge,
- revealChild: Network.wifi,
- child: actualContent,
- })]
- })
-}
-
-export default (props) => {
- const networkList = Box({
- vertical: true,
- className: 'spacing-v-10',
- children: [Overlay({
- passThrough: true,
- child: Scrollable({
- vexpand: true,
- child: Box({
- attribute: {
- 'updateNetworks': (self) => {
- const accessPoints = Network.wifi?.access_points || [];
- self.children = Object.values(accessPoints.reduce((a, accessPoint) => {
- // Only keep max strength networks by ssid
- if (!a[accessPoint.ssid] || a[accessPoint.ssid].strength < accessPoint.strength) {
- a[accessPoint.ssid] = accessPoint;
- a[accessPoint.ssid].active |= accessPoint.active;
- }
-
- return a;
- }, {})).map(n => WifiNetwork(n));
- },
- },
- vertical: true,
- className: 'spacing-v-5 sidebar-centermodules-scrollgradient-bottom-contentmargin',
- setup: (self) => self.hook(Network, self.attribute.updateNetworks),
- }),
- }),
- overlays: [Box({
- className: 'sidebar-centermodules-scrollgradient-bottom'
- })]
- })]
- });
- const bottomBar = Box({
- homogeneous: true,
- children: [Button({
- hpack: 'center',
- className: 'txt-small txt sidebar-centermodules-bottombar-button',
- onClicked: () => {
- execAsync(['bash', '-c', userOptions.apps.network]).catch(print);
- closeEverything();
- },
- label: getString('More'),
- setup: setupCursorHover,
- })],
- })
- return Box({
- ...props,
- className: 'spacing-v-10',
- vertical: true,
- children: [
- CurrentNetwork(),
- networkList,
- bottomBar,
- ]
- });
-}
\ No newline at end of file
diff --git a/.config/ags/modules/sideright/main.js b/.config/ags/modules/sideright/main.js
deleted file mode 100644
index 883c7f0e6..000000000
--- a/.config/ags/modules/sideright/main.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import PopupWindow from '../.widgethacks/popupwindow.js';
-import SidebarRight from "./sideright.js";
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-const { Box } = Widget;
-import clickCloseRegion from '../.commonwidgets/clickcloseregion.js';
-
-export default () => PopupWindow({
- keymode: 'on-demand',
- anchor: ['right', 'top', 'bottom'],
- name: 'sideright',
- layer: 'top',
- child: Box({
- children: [
- clickCloseRegion({ name: 'sideright', multimonitor: false, fillMonitor: 'horizontal' }),
- SidebarRight(),
- ]
- })
-});
diff --git a/.config/ags/modules/sideright/quicktoggles.js b/.config/ags/modules/sideright/quicktoggles.js
deleted file mode 100644
index 41d6ee634..000000000
--- a/.config/ags/modules/sideright/quicktoggles.js
+++ /dev/null
@@ -1,296 +0,0 @@
-const { GLib } = imports.gi;
-import App from 'resource:///com/github/Aylur/ags/app.js';
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-
-import Bluetooth from 'resource:///com/github/Aylur/ags/service/bluetooth.js';
-import Network from 'resource:///com/github/Aylur/ags/service/network.js';
-const { execAsync, exec } = Utils;
-import { BluetoothIndicator, NetworkIndicator } from '../.commonwidgets/statusicons.js';
-import { setupCursorHover } from '../.widgetutils/cursorhover.js';
-import { MaterialIcon } from '../.commonwidgets/materialicon.js';
-import { sidebarOptionsStack } from './sideright.js';
-
-export const ToggleIconWifi = (props = {}) => Widget.Button({
- className: 'txt-small sidebar-iconbutton',
- tooltipText: getString('Wifi | Right-click to configure'),
- onClicked: () => Network.toggleWifi(),
- onSecondaryClickRelease: () => {
- execAsync(['bash', '-c', `${userOptions.apps.network}`]).catch(print);
- closeEverything();
- },
- child: NetworkIndicator(),
- setup: (self) => {
- setupCursorHover(self);
- self.hook(Network, button => {
- button.toggleClassName('sidebar-button-active', [Network.wifi?.internet, Network.wired?.internet].includes('connected'))
- button.tooltipText = (`${Network.wifi?.ssid} | ${getString("Right-click to configure")}` || getString('Unknown'));
- });
- },
- ...props,
-});
-
-export const ToggleIconBluetooth = (props = {}) => Widget.Button({
- className: 'txt-small sidebar-iconbutton',
- tooltipText: getString('Bluetooth | Right-click to configure'),
- onClicked: () => {
- const status = Bluetooth?.enabled;
- if (status)
- exec('rfkill block bluetooth');
- else
- exec('rfkill unblock bluetooth');
- },
- onSecondaryClickRelease: () => {
- execAsync(['bash', '-c', `${userOptions.apps.bluetooth}`]).catch(print);
- closeEverything();
- },
- child: BluetoothIndicator(),
- setup: (self) => {
- setupCursorHover(self);
- self.hook(Bluetooth, button => {
- button.toggleClassName('sidebar-button-active', Bluetooth?.enabled)
- });
- },
- ...props,
-});
-
-export const HyprToggleIcon = async (icon, name, hyprlandConfigValue, props = {}) => {
- try {
- return Widget.Button({
- className: 'txt-small sidebar-iconbutton',
- tooltipText: `${name}`,
- onClicked: (button) => {
- // Set the value to 1 - value
- Utils.execAsync(`hyprctl -j getoption ${hyprlandConfigValue}`).then((result) => {
- const currentOption = JSON.parse(result).int;
- execAsync(['bash', '-c', `hyprctl keyword ${hyprlandConfigValue} ${1 - currentOption} &`]).catch(print);
- button.toggleClassName('sidebar-button-active', currentOption == 0);
- }).catch(print);
- },
- child: MaterialIcon(icon, 'norm', { hpack: 'center' }),
- setup: button => {
- button.toggleClassName('sidebar-button-active', JSON.parse(Utils.exec(`hyprctl -j getoption ${hyprlandConfigValue}`)).int == 1);
- setupCursorHover(button);
- },
- ...props,
- })
- } catch {
- return null;
- }
-}
-
-export const ModuleNightLight = async (props = {}) => {
- if (!exec(`bash -c 'command -v gammastep'`)) return null;
- return Widget.Button({
- attribute: {
- enabled: false,
- },
- className: 'txt-small sidebar-iconbutton',
- tooltipText: getString('Night Light'),
- onClicked: (self) => {
- self.attribute.enabled = !self.attribute.enabled;
- self.toggleClassName('sidebar-button-active', self.attribute.enabled);
- if (self.attribute.enabled) Utils.execAsync('gammastep').catch(print)
- else Utils.execAsync('pkill gammastep')
- .then(() => {
- // disable the button until fully terminated to avoid race
- self.sensitive = false;
- const source = setInterval(() => {
- Utils.execAsync('pkill -0 gammastep')
- .catch(() => {
- self.sensitive = true;
- source.destroy();
- });
- }, 500);
- })
- .catch(print);
- },
- child: MaterialIcon('nightlight', 'norm'),
- setup: (self) => {
- setupCursorHover(self);
- self.attribute.enabled = !!exec('pidof gammastep');
- self.toggleClassName('sidebar-button-active', self.attribute.enabled);
- },
- ...props,
- });
-}
-
-export const ModuleCloudflareWarp = async (props = {}) => {
- if (!exec(`bash -c 'command -v warp-cli'`)) return null;
- return Widget.Button({
- attribute: {
- enabled: false,
- },
- className: 'txt-small sidebar-iconbutton',
- tooltipText: getString('Cloudflare WARP'),
- onClicked: (self) => {
- self.attribute.enabled = !self.attribute.enabled;
- self.toggleClassName('sidebar-button-active', self.attribute.enabled);
- if (self.attribute.enabled) Utils.execAsync('warp-cli connect').catch(print)
- else Utils.execAsync('warp-cli disconnect').catch(print);
- },
- child: Widget.Icon({
- icon: 'cloudflare-dns-symbolic',
- className: 'txt-norm',
- }),
- setup: (self) => {
- setupCursorHover(self);
- self.attribute.enabled = !exec(`bash -c 'warp-cli status | grep Disconnected'`);
- self.toggleClassName('sidebar-button-active', self.attribute.enabled);
- },
- ...props,
- });
-}
-
-export const ModuleInvertColors = async (props = {}) => {
- try {
- const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
- return Widget.Button({
- className: 'txt-small sidebar-iconbutton',
- tooltipText: getString('Color inversion'),
- onClicked: (button) => {
- // const shaderPath = JSON.parse(exec('hyprctl -j getoption decoration:screen_shader')).str;
- Hyprland.messageAsync('j/getoption decoration:screen_shader')
- .then((output) => {
- const shaderPath = JSON.parse(output)["str"].trim();
- if (shaderPath != "[[EMPTY]]" && shaderPath != "") {
- execAsync(['bash', '-c', `hyprctl keyword decoration:screen_shader '[[EMPTY]]'`]).catch(print);
- button.toggleClassName('sidebar-button-active', false);
- }
- else {
- Hyprland.messageAsync(`j/keyword decoration:screen_shader ${GLib.get_user_config_dir()}/hypr/shaders/invert.frag`)
- .catch(print);
- button.toggleClassName('sidebar-button-active', true);
- }
- })
- },
- child: MaterialIcon('invert_colors', 'norm'),
- setup: setupCursorHover,
- ...props,
- })
- } catch {
- return null;
- };
-}
-
-export const ModuleRawInput = async (props = {}) => {
- try {
- const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
- return Widget.Button({
- className: 'txt-small sidebar-iconbutton',
- tooltipText: 'Raw input',
- onClicked: (button) => {
- Hyprland.messageAsync('j/getoption input:accel_profile')
- .then((output) => {
- const value = JSON.parse(output)["str"].trim();
- if (value != "[[EMPTY]]" && value != "") {
- execAsync(['bash', '-c', `hyprctl keyword input:accel_profile '[[EMPTY]]'`]).catch(print);
- button.toggleClassName('sidebar-button-active', false);
- }
- else {
- Hyprland.messageAsync(`j/keyword input:accel_profile flat`)
- .catch(print);
- button.toggleClassName('sidebar-button-active', true);
- }
- })
- },
- child: MaterialIcon('mouse', 'norm'),
- setup: setupCursorHover,
- ...props,
- })
- } catch {
- return null;
- };
-}
-
-export const ModuleGameMode = async (props = {}) => {
- try {
- const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
- return Widget.Button({
- className: 'txt-small sidebar-iconbutton',
- tooltipText: getString('Hyprland Game Mode'),
- onClicked: (button) => {
- Utils.execAsync(`hyprctl -j getoption animations:enabled`)
- .then((output) => {
- const enabled = JSON.parse(output)["int"] === 1;
- if (enabled) {
- execAsync(['bash', '-c', `hyprctl --batch "keyword animations:enabled 0; keyword decoration:shadow:enabled 0; keyword decoration:blur:enabled 0; keyword general:gaps_in 0; keyword general:gaps_out 0; keyword general:border_size 1; keyword decoration:rounding 0; keyword general:allow_tearing 1"`]).catch(print);
- execAsync(['gsettings', 'set', 'org.gnome.desktop.interface', 'enable-animations', 'false'])
- } else {
- execAsync(['bash', '-c', `hyprctl reload`]).catch(print);
- execAsync(['gsettings', 'set', 'org.gnome.desktop.interface', 'enable-animations', 'true'])
- }
- button.toggleClassName('sidebar-button-active', enabled);
- })
- },
- child: MaterialIcon('gamepad', 'norm'),
- setup: setupCursorHover,
- ...props,
- })
- } catch {
- return null;
- };
-}
-
-export const ModuleIdleInhibitor = (props = {}) => Widget.Button({ // TODO: Make this work
- attribute: {
- enabled: false,
- },
- className: 'txt-small sidebar-iconbutton',
- tooltipText: getString('Keep system awake'),
- onClicked: (self) => {
- self.attribute.enabled = !self.attribute.enabled;
- self.toggleClassName('sidebar-button-active', self.attribute.enabled);
- if (self.attribute.enabled) Utils.execAsync(['bash', '-c', `pidof wayland-idle-inhibitor.py || ${App.configDir}/scripts/wayland-idle-inhibitor.py`]).catch(print)
- else Utils.execAsync('pkill -f wayland-idle-inhibitor.py').catch(print);
- },
- child: MaterialIcon('coffee', 'norm'),
- setup: (self) => {
- setupCursorHover(self);
- self.attribute.enabled = !!exec('pidof wayland-idle-inhibitor.py');
- self.toggleClassName('sidebar-button-active', self.attribute.enabled);
- },
- ...props,
-});
-
-export const ModuleReloadIcon = (props = {}) => Widget.Button({
- ...props,
- className: 'txt-small sidebar-iconbutton',
- tooltipText: getString('Reload Environment config'),
- onClicked: () => {
- execAsync(['bash', '-c', 'hyprctl reload || swaymsg reload &']);
- App.closeWindow('sideright');
- },
- child: MaterialIcon('refresh', 'norm'),
- setup: button => {
- setupCursorHover(button);
- }
-})
-
-export const ModuleSettingsIcon = (props = {}) => Widget.Button({
- ...props,
- className: 'txt-small sidebar-iconbutton',
- tooltipText: getString('Open Settings'),
- onClicked: () => {
- execAsync(['bash', '-c', `${userOptions.apps.settings}`, '&']);
- App.closeWindow('sideright');
- },
- child: MaterialIcon('settings', 'norm'),
- setup: button => {
- setupCursorHover(button);
- }
-})
-
-export const ModulePowerIcon = (props = {}) => Widget.Button({
- ...props,
- className: 'txt-small sidebar-iconbutton',
- tooltipText: getString('Session'),
- onClicked: () => {
- closeEverything();
- Utils.timeout(1, () => openWindowOnAllMonitors('session'));
- },
- child: MaterialIcon('power_settings_new', 'norm'),
- setup: button => {
- setupCursorHover(button);
- }
-})
diff --git a/.config/ags/modules/sideright/sideright.js b/.config/ags/modules/sideright/sideright.js
deleted file mode 100644
index 12a01297f..000000000
--- a/.config/ags/modules/sideright/sideright.js
+++ /dev/null
@@ -1,192 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { execAsync, exec } = Utils;
-const { Box, EventBox } = Widget;
-import {
- ToggleIconBluetooth,
- ToggleIconWifi,
- HyprToggleIcon,
- ModuleNightLight,
- ModuleInvertColors,
- ModuleIdleInhibitor,
- ModuleReloadIcon,
- ModuleSettingsIcon,
- ModulePowerIcon,
- ModuleRawInput,
- ModuleGameMode,
- ModuleCloudflareWarp
-} from "./quicktoggles.js";
-import ModuleNotificationList from "./centermodules/notificationlist.js";
-import ModuleAudioControls from "./centermodules/audiocontrols.js";
-import ModuleWifiNetworks from "./centermodules/wifinetworks.js";
-import ModuleBluetooth from "./centermodules/bluetooth.js";
-import ModuleConfigure from "./centermodules/configure.js";
-import { ModuleCalendar } from "./calendar.js";
-import { getDistroIcon } from '../.miscutils/system.js';
-import { MaterialIcon } from '../.commonwidgets/materialicon.js';
-import { ExpandingIconTabContainer } from '../.commonwidgets/tabcontainer.js';
-import { checkKeybind } from '../.widgetutils/keybind.js';
-
-const QUICK_TOGGLES = {
- 'wifi': ToggleIconWifi(),
- 'bluetooth': ToggleIconBluetooth(),
- 'rawinput': await ModuleRawInput(),
- 'touchpad': await HyprToggleIcon('touchpad_mouse', 'No touchpad while typing', 'input:touchpad:disable_while_typing', {}),
- 'nightlight': await ModuleNightLight(),
- 'invertcolors': await ModuleInvertColors(),
- 'gamemode': await ModuleGameMode(),
- 'idleinhibitor': ModuleIdleInhibitor(),
- 'cloudflarewarp': await ModuleCloudflareWarp(),
-}
-
-const centerWidgets = [
- {
- name: getString('Notifications'),
- materialIcon: 'notifications',
- contentWidget: ModuleNotificationList,
- },
- {
- name: getString('Audio controls'),
- materialIcon: 'volume_up',
- contentWidget: ModuleAudioControls,
- },
- {
- name: getString('Bluetooth'),
- materialIcon: 'bluetooth',
- contentWidget: ModuleBluetooth,
- },
- {
- name: getString('Wifi networks'),
- materialIcon: 'wifi',
- contentWidget: ModuleWifiNetworks,
- onFocus: () => execAsync('nmcli dev wifi list').catch(print),
- },
- {
- name: getString('Quick config'),
- materialIcon: 'tune',
- contentWidget: ModuleConfigure,
- },
-];
-
-const timeRow = Box({
- className: 'spacing-h-10 sidebar-group-invisible-morehorizpad',
- children: [
- Widget.Icon({
- icon: getDistroIcon(),
- className: 'txt txt-larger',
- }),
- Widget.Label({
- hpack: 'center',
- className: 'txt-small txt',
- setup: (self) => {
- const getUptime = async () => {
- try {
- await execAsync(['bash', '-c', 'uptime -p']);
- return execAsync(['bash', '-c', `uptime -p | sed -e 's/...//;s/ day\\| days/d/;s/ hour\\| hours/h/;s/ minute\\| minutes/m/;s/,[^,]*//2'`]);
- } catch {
- return execAsync(['bash', '-c', 'uptime']).then(output => {
- const uptimeRegex = /up\s+((\d+)\s+days?,\s+)?((\d+):(\d+)),/;
- const matches = uptimeRegex.exec(output);
-
- if (matches) {
- const days = matches[2] ? parseInt(matches[2]) : 0;
- const hours = matches[4] ? parseInt(matches[4]) : 0;
- const minutes = matches[5] ? parseInt(matches[5]) : 0;
-
- let formattedUptime = '';
-
- if (days > 0) {
- formattedUptime += `${days} d `;
- }
- if (hours > 0) {
- formattedUptime += `${hours} h `;
- }
- formattedUptime += `${minutes} m`;
-
- return formattedUptime;
- } else {
- throw new Error('Failed to parse uptime output');
- }
- });
- }
- };
-
- self.poll(5000, label => {
- getUptime().then(upTimeString => {
- label.label = `${getString("Uptime:"
- )} ${upTimeString}`;
- }).catch(err => {
- console.error(`Failed to fetch uptime: ${err}`);
- });
- });
- },
- }),
- Widget.Box({ hexpand: true }),
- ModuleReloadIcon({ hpack: 'end' }),
- // ModuleSettingsIcon({ hpack: 'end' }), // Button does work, gnome-control-center is kinda broken
- ModulePowerIcon({ hpack: 'end' }),
- ]
-});
-
-const togglesBox = Widget.Box({
- hpack: 'center',
- className: 'sidebar-togglesbox spacing-h-5',
- children: userOptions.sidebar.quickToggles.order.map(toggle => QUICK_TOGGLES[toggle])
-})
-
-export const sidebarOptionsStack = ExpandingIconTabContainer({
- tabsHpack: 'center',
- tabSwitcherClassName: 'sidebar-icontabswitcher',
- icons: centerWidgets.map((api) => api.materialIcon),
- names: centerWidgets.map((api) => api.name),
- children: centerWidgets.map((api) => api.contentWidget()),
- onChange: (self, id) => {
- self.shown = centerWidgets[id].name;
- if (centerWidgets[id].onFocus) centerWidgets[id].onFocus();
- }
-});
-
-export default () => Box({
- vexpand: true,
- hexpand: true,
- css: 'min-width: 2px;',
- children: [
- EventBox({
- onPrimaryClick: () => App.closeWindow('sideright'),
- onSecondaryClick: () => App.closeWindow('sideright'),
- onMiddleClick: () => App.closeWindow('sideright'),
- }),
- Box({
- vertical: true,
- vexpand: true,
- className: 'sidebar-right spacing-v-15',
- children: [
- Box({
- vertical: true,
- className: 'spacing-v-5',
- children: [
- timeRow,
- togglesBox,
- ]
- }),
- Box({
- className: 'sidebar-group',
- children: [
- sidebarOptionsStack,
- ],
- }),
- ModuleCalendar(),
- ]
- }),
- ],
- setup: (self) => self
- .on('key-press-event', (widget, event) => { // Handle keybinds
- if (checkKeybind(event, userOptions.keybinds.sidebar.options.nextTab)) {
- sidebarOptionsStack.nextTab();
- }
- else if (checkKeybind(event, userOptions.keybinds.sidebar.options.prevTab)) {
- sidebarOptionsStack.prevTab();
- }
- })
- ,
-});
diff --git a/.config/ags/modules/sideright/todolist.js b/.config/ags/modules/sideright/todolist.js
deleted file mode 100644
index 39ccc500a..000000000
--- a/.config/ags/modules/sideright/todolist.js
+++ /dev/null
@@ -1,224 +0,0 @@
-import Widget from 'resource:///com/github/Aylur/ags/widget.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { Box, Button, Label, Revealer } = Widget;
-import { MaterialIcon } from '../.commonwidgets/materialicon.js';
-import { TabContainer } from '../.commonwidgets/tabcontainer.js';
-import Todo from "../../services/todo.js";
-import { setupCursorHover } from '../.widgetutils/cursorhover.js';
-
-const TodoListItem = (task, id, isDone, isEven = false) => {
- const taskName = Widget.Label({
- hexpand: true,
- xalign: 0,
- wrap: true,
- className: 'txt txt-small sidebar-todo-txt',
- label: task.content,
- selectable: true,
- });
- const actions = Box({
- hpack: 'end',
- className: 'spacing-h-5 sidebar-todo-actions',
- children: [
- Widget.Button({ // Check/Uncheck
- vpack: 'center',
- className: 'txt sidebar-todo-item-action',
- child: MaterialIcon(`${isDone ? 'remove_done' : 'check'}`, 'norm', { vpack: 'center' }),
- onClicked: (self) => {
- const contentWidth = todoContent.get_allocated_width();
- crosser.toggleClassName('sidebar-todo-crosser-crossed', true);
- crosser.css = `margin-left: -${contentWidth}px;`;
- Utils.timeout(200, () => {
- widgetRevealer.revealChild = false;
- })
- Utils.timeout(350, () => {
- if (isDone)
- Todo.uncheck(id);
- else
- Todo.check(id);
- })
- },
- setup: setupCursorHover,
- }),
- Widget.Button({ // Remove
- vpack: 'center',
- className: 'txt sidebar-todo-item-action',
- child: MaterialIcon('delete_forever', 'norm', { vpack: 'center' }),
- onClicked: () => {
- const contentWidth = todoContent.get_allocated_width();
- crosser.toggleClassName('sidebar-todo-crosser-removed', true);
- crosser.css = `margin-left: -${contentWidth}px;`;
- Utils.timeout(200, () => {
- widgetRevealer.revealChild = false;
- })
- Utils.timeout(350, () => {
- Todo.remove(id);
- })
- },
- setup: setupCursorHover,
- }),
- ]
- })
- const crosser = Widget.Box({
- className: 'sidebar-todo-crosser',
- });
- const todoContent = Widget.Box({
- className: 'sidebar-todo-item spacing-h-5',
- children: [
- Widget.Box({
- vertical: true,
- children: [
- taskName,
- actions,
- ]
- }),
- crosser,
- ]
- });
- const widgetRevealer = Widget.Revealer({
- revealChild: true,
- transition: 'slide_down',
- transitionDuration: userOptions.animations.durationLarge,
- child: todoContent,
- })
- return Box({
- homogeneous: true,
- children: [widgetRevealer]
- });
-}
-
-const todoItems = (isDone) => Widget.Scrollable({
- hscroll: 'never',
- vscroll: 'automatic',
- child: Widget.Box({
- vertical: true,
- className: 'spacing-v-5',
- setup: (self) => self
- .hook(Todo, (self) => {
- self.children = Todo.todo_json.map((task, i) => {
- if (task.done != isDone) return null;
- return TodoListItem(task, i, isDone);
- })
- if (self.children.length == 0) {
- self.homogeneous = true;
- self.children = [
- Widget.Box({
- hexpand: true,
- vertical: true,
- vpack: 'center',
- className: 'txt txt-subtext',
- children: [
- MaterialIcon(`${isDone ? 'checklist' : 'check_circle'}`, 'gigantic'),
- Label({ label: `${isDone ? getString('Finished tasks will go here') : getString('Nothing here!')}` })
- ]
- })
- ]
- }
- else self.homogeneous = false;
- }, 'updated')
- ,
- }),
- setup: (listContents) => {
- const vScrollbar = listContents.get_vscrollbar();
- vScrollbar.get_style_context().add_class('sidebar-scrollbar');
- }
-});
-
-const UndoneTodoList = () => {
- const newTaskButton = Revealer({
- transition: 'slide_left',
- transitionDuration: userOptions.animations.durationLarge,
- revealChild: true,
- child: Button({
- className: 'txt-small sidebar-todo-new',
- halign: 'end',
- vpack: 'center',
- label: getString('+ New task'),
- setup: setupCursorHover,
- onClicked: (self) => {
- newTaskButton.revealChild = false;
- newTaskEntryRevealer.revealChild = true;
- confirmAddTask.revealChild = true;
- cancelAddTask.revealChild = true;
- newTaskEntry.grab_focus();
- }
- })
- });
- const cancelAddTask = Revealer({
- transition: 'slide_right',
- transitionDuration: userOptions.animations.durationLarge,
- revealChild: false,
- child: Button({
- className: 'txt-norm icon-material sidebar-todo-add',
- halign: 'end',
- vpack: 'center',
- label: 'close',
- setup: setupCursorHover,
- onClicked: (self) => {
- newTaskEntryRevealer.revealChild = false;
- confirmAddTask.revealChild = false;
- cancelAddTask.revealChild = false;
- newTaskButton.revealChild = true;
- newTaskEntry.text = '';
- }
- })
- });
- const newTaskEntry = Widget.Entry({
- // hexpand: true,
- vpack: 'center',
- className: 'txt-small sidebar-todo-entry',
- placeholderText: getString('Add a task...'),
- onAccept: ({ text }) => {
- if (text == '') return;
- Todo.add(text)
- newTaskEntry.text = '';
- },
- onChange: ({ text }) => confirmAddTask.child.toggleClassName('sidebar-todo-add-available', text != ''),
- });
- const newTaskEntryRevealer = Revealer({
- transition: 'slide_right',
- transitionDuration: userOptions.animations.durationLarge,
- revealChild: false,
- child: newTaskEntry,
- });
- const confirmAddTask = Revealer({
- transition: 'slide_right',
- transitionDuration: userOptions.animations.durationLarge,
- revealChild: false,
- child: Button({
- className: 'txt-norm icon-material sidebar-todo-add',
- halign: 'end',
- vpack: 'center',
- label: 'arrow_upward',
- setup: setupCursorHover,
- onClicked: (self) => {
- if (newTaskEntry.text == '') return;
- Todo.add(newTaskEntry.text);
- newTaskEntry.text = '';
- }
- })
- });
- return Box({ // The list, with a New button
- vertical: true,
- className: 'spacing-v-5',
- setup: (box) => {
- box.pack_start(todoItems(false), true, true, 0);
- box.pack_start(Box({
- setup: (self) => {
- self.pack_start(cancelAddTask, false, false, 0);
- self.pack_start(newTaskEntryRevealer, true, true, 0);
- self.pack_start(confirmAddTask, false, false, 0);
- self.pack_start(newTaskButton, false, false, 0);
- }
- }), false, false, 0);
- },
- });
-}
-
-export const TodoWidget = () => TabContainer({
- icons: ['format_list_bulleted', 'task_alt'],
- names: [getString('Unfinished'), getString('Done')],
- children: [
- UndoneTodoList(),
- todoItems(true),
- ]
-})
diff --git a/.config/ags/scripts/README.md b/.config/ags/scripts/README.md
deleted file mode 100644
index 6d79a5145..000000000
--- a/.config/ags/scripts/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# scripts folder
-- For ARM devices, you have to compile C++ files yourself. If there are none, yippee
-- It is advised to use services instead of listening/polling scripts, so everything here are just scripts for actions
\ No newline at end of file
diff --git a/.config/ags/scripts/ags/agsconfigurator.py b/.config/ags/scripts/ags/agsconfigurator.py
deleted file mode 100755
index 72e9b7400..000000000
--- a/.config/ags/scripts/ags/agsconfigurator.py
+++ /dev/null
@@ -1,137 +0,0 @@
-#!/usr/bin/env -S\_/bin/sh\_-c\_"source\_\$(eval\_echo\_\$ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate&&exec\_python\_-E\_"\$0"\_"\$@""
-import argparse
-import json
-import sys
-import ast
-import re
-
-def parse_value(value):
- """Parse the value into its appropriate Python type (e.g., bool, int, float, list, dict, or string)."""
- try:
- return json.loads(value)
- except json.JSONDecodeError: # Fallback to string if parsing fails
- return value
-
-def remove_trailing_commas(json_string):
- """Remove trailing commas from JSON-like structures."""
- return re.sub(r',\s*([\}\]])', r'\1', json_string)
-
-def strip_comments_except_leading(lines):
- """
- Removes all `//` and `/* ... */` comments, except for leading `//` comments at the start.
- Ensures `//` inside strings is preserved.
- Returns (preserved_comments, cleaned_json).
- """
- preserved_comments = []
- json_lines = []
- in_block_comment = False
- in_string = False
- escaped = False
-
- for line in lines:
- stripped = line.strip()
-
- # Handle block comments
- if in_block_comment:
- if "*/" in stripped:
- in_block_comment = False
- continue
- if stripped.startswith("/*"):
- in_block_comment = True
- continue
-
- # Preserve leading `//` comments at the very start
- if stripped.startswith("//") and not json_lines:
- preserved_comments.append(line)
- continue
-
- # Process line while tracking if inside a string
- new_line = []
- i = 0
- while i < len(line):
- char = line[i]
-
- if char == '"' or char == "'": # Detect string start
- if not in_string:
- in_string = char
- elif in_string == char and not escaped:
- in_string = False
- elif char == "\\" and in_string: # Handle escape sequences
- escaped = not escaped
- else:
- escaped = False
-
- # Remove inline `//` comments only if not inside a string
- if char == "/" and i + 1 < len(line) and line[i + 1] == "/" and not in_string:
- break # Stop processing the line at `//` (comment start)
-
- new_line.append(char)
- i += 1
-
- cleaned_line = "".join(new_line).rstrip()
- if cleaned_line:
- json_lines.append(cleaned_line + "\n")
-
- return preserved_comments, json_lines
-
-def update_json(file_path, key, value=None, reset=False):
- try:
- with open(file_path, 'r') as file:
- lines = file.readlines()
-
- # Separate leading comments and clean JSON
- preserved_comments, json_lines = strip_comments_except_leading(lines)
- json_string = "".join(json_lines)
- json_string = remove_trailing_commas(json_string)
-
- # Convert the cleaned string into a JSON object
- try:
- json_data = json.loads(json_string)
- except json.JSONDecodeError:
- print(f"Error decoding JSON in file: {file_path}")
- sys.exit(1)
-
- # Navigate through the key (e.g., 'search.enableFeatures.actions')
- keys = key.split('.')
- data = json_data
- for k in keys[:-1]:
- data = data.setdefault(k, {})
-
- # Update or delete the key
- if reset:
- if keys[-1] in data:
- del data[keys[-1]]
- print(f"Successfully removed {key} from {file_path}")
- else:
- print(f"Key {key} not found in {file_path}")
- else:
- data[keys[-1]] = value
- print(f"Successfully updated {key} to {value} in {file_path}")
-
- # Write back only valid JSON (with preserved leading comments)
- with open(file_path, 'w') as file:
- file.writelines(preserved_comments) # Restore leading comments
- json.dump(json_data, file, indent=4)
- file.write("\n") # Ensure a newline at the end
-
- except FileNotFoundError:
- print(f"File not found: {file_path}")
- sys.exit(1)
- except Exception as e:
- print(f"Error: {str(e)}")
- sys.exit(1)
-
-if __name__ == "__main__":
- parser = argparse.ArgumentParser(description="Update or remove a key from a JSON configuration file")
- parser.add_argument('--key', required=True, help="The key to be updated or removed (e.g., 'search.enableFeatures.actions')")
- parser.add_argument('--file', required=True, help="The path to the target JSON file")
- parser.add_argument('--value', help="The new value to assign (e.g., 'true', '42', '[1, 2, 3]')")
- parser.add_argument('--reset', action='store_true', help="If set, the key will be removed from the JSON file")
-
- args = parser.parse_args()
-
- value = None
- if args.value:
- value = parse_value(args.value)
-
- update_json(args.file, args.key, value, reset=args.reset)
diff --git a/.config/ags/scripts/ai/license_show-loaded-ollama-models.txt b/.config/ags/scripts/ai/license_show-loaded-ollama-models.txt
deleted file mode 100644
index 261eeb9e9..000000000
--- a/.config/ags/scripts/ai/license_show-loaded-ollama-models.txt
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/.config/ags/scripts/ai/primary-buffer-query.sh b/.config/ags/scripts/ai/primary-buffer-query.sh
deleted file mode 100755
index a4356b4b6..000000000
--- a/.config/ags/scripts/ai/primary-buffer-query.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env bash
-
-# Default system prompt
-SYSTEM_PROMPT="You are a helpful, quick assistant that provides brief and concise explanation \
-to given content in at most 100 characters. If the given content is not in English, translate \
-it to English. If the content is an English word, provide its meaning. If the content is a name, \
-provide some info about it. For a math expression, provide a simplification, \
-each step on a line following this style: \`2x=11 (subtract 7 from both sides)\`. \
-If you do not know the answer, simply say 'No info available'. \
-Only respond for the appropriate case and use as little text as possible.\
-The content:"
-
-first_loaded_model=$("$(dirname "$0")/show-loaded-ollama-models.sh" -j | jq -r '.[0].model' 2>/dev/null) || first_loaded_model=""
-model=${first_loaded_model:-"llama3.2"}
-
-# Parse command-line arguments
-while [[ "$#" -gt 0 ]]; do
- case $1 in
- --model) model="$2"; shift ;; # Set the model from the flag
- *) echo "Unknown parameter: $1"; exit 1 ;;
- esac
- shift
-done
-
-# Combine the system prompt with the clipboard content
-content=$(wl-paste -p | tr '\n' ' ')
-prompt="$SYSTEM_PROMPT $content"
-
-# Make the API call with the specified or default model
-response=$(curl http://localhost:11434/api/generate -d \
- "{\"model\": \"$model\",\"prompt\": \"$prompt\",\"stream\": false}" \
- | jq -r '.response')
-
-# Check if content is a single line and no longer than 30 characters
-if [[ ${#content} -le 30 && "$content" != *$'\n'* ]]; then
- notify-send --app-name="primary-buffer-query" --expire-time=10000 \
- "$content" "$response"
-else
- notify-send --app-name="primary-buffer-query" --expire-time=10000 \
- "AI Response" "$response"
-fi
diff --git a/.config/ags/scripts/ai/show-installed-ollama-models.sh b/.config/ags/scripts/ai/show-installed-ollama-models.sh
deleted file mode 100755
index e56ac766a..000000000
--- a/.config/ags/scripts/ai/show-installed-ollama-models.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env bash
-
-# Get the list, skip the header, and extract the first column (model names)
-model_names=$(ollama list | tail -n +2 | awk '{print $1}')
-
-# Build a JSON array
-json_array="["
-for name in $model_names; do
- json_array+="\"$name\","
-done
-
-# Remove trailing comma and close the array
-json_array="${json_array%,}]"
-
-# Output the JSON array
-echo "$json_array"
diff --git a/.config/ags/scripts/ai/show-loaded-ollama-models.sh b/.config/ags/scripts/ai/show-loaded-ollama-models.sh
deleted file mode 100755
index 8dc88780d..000000000
--- a/.config/ags/scripts/ai/show-loaded-ollama-models.sh
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/bin/bash
-
-# From strikeoncmputrz/LLM_Scripts
-# License: Apache-2.0, can be found in the same folder as this script
-
-# Global Vars
-ollama_url=http://localhost
-port="11434"
-blobs=()
-model_name_paths=()
-
-
-#Parse arguments
-while [ "$#" -gt 0 ]; do
- case $1 in
- -h|--help)
- echo
- echo " Identifies Ollama models running on this operating system by parsing running processes."
- echo
- echo " Usage: $0 [options]"
- echo
- echo " Options:"
- echo " -j, --json_output Prints result as a json object. Other output disabled. (Default: false)"
- echo " -p, --port [port number] Specify Ollama Server port (Default: 11434)"
- echo " -u, --ollama_url [url] Specify Ollama Server URL (Default: http://localhost)"
- echo
- echo " Dependencies: jq"
- exit 0
- ;;
- -j|--json_output)
- json_out=1
- shift 1
- ;;
- -u|--ollama_url)
- ollama_url=$2
- shift 2
- ;;
- -p|--port)
- port=$2
- shift 2
- ;;
- *)
- echo "Unknown option: $1"
- exit 1
- ;;
- esac
-done
-
-compare_running_models_and_modelfiles() {
- json_match=()
- json_output=()
- local matching_models=()
- OLDIFS=$IFS
- for ((i=0; i<${#model_name_paths[@]}; i++)); do # Iterate over the array of modelname,blob-path
- for blob in "${blobs[@]}"; do
- IFS=',', read -ra fields <<< "${model_name_paths[i]}" # Split the string into parts
- if [ "${fields[1]}" == "$blob" ]; then # Check if current 'field' matches a blob
- matching_models+=( '{ "model": "'"${fields[0]}"'", "path": "'"${fields[1]}"'"}') # Add to list of matching models
- fi
- done
- done
-
- if [ -z "$json_out" ]; then
- echo -e "\nModel Found: \n $(echo ${matching_models[*]} | jq '.' | sed s/[{}]//g) \n"
- else
- local json_match="${matching_models[*]}"
- json_output=$(echo $json_match | jq -c -s .)
- echo "$json_output"
- fi
- IFS=$OLDIFS
-}
-
-get_running_model_paths() {
- blobs=$(ps aux | grep -- '--model' | grep -v grep | grep -Po '(?<=--model\s).*' | cut -d ' ' -f1)
- if [ -z "$blobs" ]; then
- echo -e "\n\n Warning: No running Ollama models detected!\n"
- exit 0
- fi
-}
-
-parse_modelfiles() {
- if [ -z "$json_out" ]; then
- echo -e "\nConnecting to $ollama_url:$port\n"
- if [ -z "$(curl -s $ollama_url:$port)" ]; then
- echo -e "Could not connect to Ollama. Check the ollama_url parameter and that the server is running\n"
- exit 1
- fi
- curl -s "$ollama_url:$port"
- fi
- local models=( $(curl -s "$ollama_url:$port/api/tags" | jq -r '.models[].name') )
- for model in "${models[@]}"; do
- local modelfile=$(curl -s "$ollama_url:$port/api/show" -d '{ "name": "'"$model"'", "modelfile": true }' | jq -r '.modelfile')
- model_name_paths+=($model,$(echo "$modelfile" | awk '/^FROM/{print $2}'))
- done
-}
-
-parse_modelfiles
-get_running_model_paths
-compare_running_models_and_modelfiles
diff --git a/.config/ags/scripts/hyprland/get_keybinds.py b/.config/ags/scripts/hyprland/get_keybinds.py
deleted file mode 100755
index 559ba8a47..000000000
--- a/.config/ags/scripts/hyprland/get_keybinds.py
+++ /dev/null
@@ -1,222 +0,0 @@
-#!/usr/bin/env -S\_/bin/sh\_-c\_"source\_\$(eval\_echo\_\$ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate&&exec\_python\_-E\_"\$0"\_"\$@""
-import argparse
-import re
-import os
-from os.path import expandvars as os_expandvars
-from typing import Dict, List
-
-TITLE_REGEX = "#+!"
-HIDE_COMMENT = "[hidden]"
-MOD_SEPARATORS = ['+', ' ']
-COMMENT_BIND_PATTERN = "#/#"
-
-parser = argparse.ArgumentParser(description='Hyprland keybind reader')
-parser.add_argument('--path', type=str, default="$HOME/.config/hypr/hyprland.conf", help='path to keybind file (sourcing isn\'t supported)')
-args = parser.parse_args()
-content_lines = []
-reading_line = 0
-
-# Little Parser made for hyprland keybindings conf file
-Variables: Dict[str, str] = {}
-
-
-class KeyBinding(dict):
- def __init__(self, mods, key, dispatcher, params, comment) -> None:
- self["mods"] = mods
- self["key"] = key
- self["dispatcher"] = dispatcher
- self["params"] = params
- self["comment"] = comment
-
-class Section(dict):
- def __init__(self, children, keybinds, name) -> None:
- self["children"] = children
- self["keybinds"] = keybinds
- self["name"] = name
-
-
-def read_content(path: str) -> str:
- if (not os.access(os.path.expanduser(os.path.expandvars(path)), os.R_OK)):
- return ("error")
- with open(os.path.expanduser(os.path.expandvars(path)), "r") as file:
- return file.read()
-
-
-def autogenerate_comment(dispatcher: str, params: str = "") -> str:
- match dispatcher:
-
- case "resizewindow":
- return "Resize window"
-
- case "movewindow":
- if(params == ""):
- return "Move window"
- else:
- return "Window: move in {} direction".format({
- "l": "left",
- "r": "right",
- "u": "up",
- "d": "down",
- }.get(params, "null"))
-
- case "pin":
- return "Window: pin (show on all workspaces)"
-
- case "splitratio":
- return "Window split ratio {}".format(params)
-
- case "togglefloating":
- return "Float/unfloat window"
-
- case "resizeactive":
- return "Resize window by {}".format(params)
-
- case "killactive":
- return "Close window"
-
- case "fullscreen":
- return "Toggle {}".format(
- {
- "0": "fullscreen",
- "1": "maximization",
- "2": "fullscreen on Hyprland's side",
- }.get(params, "null")
- )
-
- case "fakefullscreen":
- return "Toggle fake fullscreen"
-
- case "workspace":
- if params == "+1":
- return "Workspace: focus right"
- elif params == "-1":
- return "Workspace: focus left"
- return "Focus workspace {}".format(params)
-
- case "movefocus":
- return "Window: move focus {}".format(
- {
- "l": "left",
- "r": "right",
- "u": "up",
- "d": "down",
- }.get(params, "null")
- )
-
- case "swapwindow":
- return "Window: swap in {} direction".format(
- {
- "l": "left",
- "r": "right",
- "u": "up",
- "d": "down",
- }.get(params, "null")
- )
-
- case "movetoworkspace":
- if params == "+1":
- return "Window: move to right workspace (non-silent)"
- elif params == "-1":
- return "Window: move to left workspace (non-silent)"
- return "Window: move to workspace {} (non-silent)".format(params)
-
- case "movetoworkspacesilent":
- if params == "+1":
- return "Window: move to right workspace"
- elif params == "-1":
- return "Window: move to right workspace"
- return "Window: move to workspace {}".format(params)
-
- case "togglespecialworkspace":
- return "Workspace: toggle special"
-
- case "exec":
- return "Execute: {}".format(params)
-
- case _:
- return ""
-
-def get_keybind_at_line(line_number, line_start = 0):
- global content_lines
- line = content_lines[line_number]
- _, keys = line.split("=", 1)
- keys, *comment = keys.split("#", 1)
-
- mods, key, dispatcher, *params = list(map(str.strip, keys.split(",", 4)))
- params = "".join(map(str.strip, params))
-
- # Remove empty spaces
- comment = list(map(str.strip, comment))
- # Add comment if it exists, else generate it
- if comment:
- comment = comment[0]
- if comment.startswith("[hidden]"):
- return None
- else:
- comment = autogenerate_comment(dispatcher, params)
-
- if mods:
- modstring = mods + MOD_SEPARATORS[0] # Add separator at end to ensure last mod is read
- mods = []
- p = 0
- for index, char in enumerate(modstring):
- if(char in MOD_SEPARATORS):
- if(index - p > 1):
- mods.append(modstring[p:index])
- p = index+1
- else:
- mods = []
-
- return KeyBinding(mods, key, dispatcher, params, comment)
-
-def get_binds_recursive(current_content, scope):
- global content_lines
- global reading_line
- # print("get_binds_recursive({0}, {1}) [@L{2}]".format(current_content, scope, reading_line + 1))
- while reading_line < len(content_lines): # TODO: Adjust condition
- line = content_lines[reading_line]
- heading_search_result = re.search(TITLE_REGEX, line)
- # print("Read line {0}: {1}\tisHeading: {2}".format(reading_line + 1, content_lines[reading_line], "[{0}, {1}, {2}]".format(heading_search_result.start(), heading_search_result.start() == 0, ((heading_search_result != None) and (heading_search_result.start() == 0))) if heading_search_result != None else "No"))
- if ((heading_search_result != None) and (heading_search_result.start() == 0)): # Found title
- # Determine scope
- heading_scope = line.find('!')
- # Lower? Return
- if(heading_scope <= scope):
- reading_line -= 1
- return current_content
-
- section_name = line[(heading_scope+1):].strip()
- # print("[[ Found h{0} at line {1} ]] {2}".format(heading_scope, reading_line+1, content_lines[reading_line]))
- reading_line += 1
- current_content["children"].append(get_binds_recursive(Section([], [], section_name), heading_scope))
-
- elif line.startswith(COMMENT_BIND_PATTERN):
- keybind = get_keybind_at_line(reading_line, line_start=len(COMMENT_BIND_PATTERN))
- if(keybind != None):
- current_content["keybinds"].append(keybind)
-
- elif line == "" or not line.lstrip().startswith("bind"): # Comment, ignore
- pass
-
- else: # Normal keybind
- keybind = get_keybind_at_line(reading_line)
- if(keybind != None):
- current_content["keybinds"].append(keybind)
-
- reading_line += 1
-
- return current_content;
-
-def parse_keys(path: str) -> Dict[str, List[KeyBinding]]:
- global content_lines
- content_lines = read_content(path).splitlines()
- if content_lines[0] == "error":
- return "error"
- return get_binds_recursive(Section([], [], ""), 0)
-
-
-if __name__ == "__main__":
- import json
-
- ParsedKeys = parse_keys(args.path)
- print(json.dumps(ParsedKeys))
diff --git a/.config/ags/scripts/hyprland/hyprconfigurator.py b/.config/ags/scripts/hyprland/hyprconfigurator.py
deleted file mode 100755
index 1a9855ebf..000000000
--- a/.config/ags/scripts/hyprland/hyprconfigurator.py
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/usr/bin/env -S\_/bin/sh\_-xc\_"source\_\$(eval\_echo\_\$ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate&&exec\_python\_-E\_"\$0"\_"\$@""
-import argparse
-import re
-import os
-
-def edit_hyprland_config(file_path, key, value, reset):
- try:
- with open(file_path, 'r') as file:
- lines = file.readlines()
- except FileNotFoundError:
- print(f"Error: File '{file_path}' not found.")
- return
-
- key_pattern = re.compile(rf'^\s*{re.escape(key)}\s*=')
- new_lines = []
- found = False
-
- for line in lines:
- if key_pattern.match(line):
- found = True
- if reset:
- continue # Skip this line to remove the key
- line = f"{key} = {value}\n"
- new_lines.append(line)
-
- if not found and not reset:
- new_lines.append(f"{key} = {value}\n")
-
- with open(file_path, 'w') as file:
- file.writelines(new_lines)
-
- if reset:
- print(f"Removed '{key}' from '{file_path}'")
- else:
- print(f"Updated '{file_path}' with {key} = {value}")
-
-if __name__ == "__main__":
- parser = argparse.ArgumentParser(description="Edit a Hyprland config file.")
- parser.add_argument("--file", default="~/.config/hypr/hyprland.conf", help="Path to the Hyprland config file (default: ~/.config/hypr/hyprland.conf).")
- parser.add_argument("--key", required=True, help="Configuration key to modify or remove.")
- parser.add_argument("--value", help="New value for the configuration key (optional).", default=None)
- parser.add_argument("--reset", action="store_true", help="Remove the specified key from the config file.")
- args = parser.parse_args()
-
- file_path = os.path.expanduser(args.file)
-
- if args.reset and args.value:
- print("Error: --reset and --value cannot be used together.")
- else:
- edit_hyprland_config(file_path, args.key, args.value or "", args.reset)
-
\ No newline at end of file
diff --git a/.config/ags/scripts/hyprland/workspace_action.sh b/.config/ags/scripts/hyprland/workspace_action.sh
deleted file mode 100755
index a43badfc8..000000000
--- a/.config/ags/scripts/hyprland/workspace_action.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/usr/bin/env bash
-hyprctl dispatch "$1" $(((($(hyprctl activeworkspace -j | jq -r .id) - 1) / 10) * 10 + $2))
diff --git a/.config/ags/scripts/network_scripts/network_bandwidth.py b/.config/ags/scripts/network_scripts/network_bandwidth.py
deleted file mode 100755
index fa4817a8e..000000000
--- a/.config/ags/scripts/network_scripts/network_bandwidth.py
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/env -S\_/bin/sh\_-xc\_"source\_\$(eval\_echo\_\$ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate&&exec\_python\_-E\_"\$0"\_"\$@""
-
-
-from time import sleep
-import sys
-import psutil
-
-try:
- direction = sys.argv[1]
-except IndexError:
- direction = "recv"
-
-init_bytes = final_bytes = 0
-
-match direction:
- case "recv":
- init_bytes = psutil.net_io_counters().bytes_recv
- sleep(1)
- final_bytes = psutil.net_io_counters().bytes_recv
-
- case "sent":
- init_bytes = psutil.net_io_counters().bytes_sent
- sleep(1)
- final_bytes = psutil.net_io_counters().bytes_sent
-
- case _:
- print(f"wrong direction: {direction}")
- sys.exit()
-
-i = 0
-divider = 1000
-bandwidth = int((final_bytes - init_bytes))
-units = ["B", "KB", "MB", "GB", "TB", "PB", "EB"]
-
-while bandwidth >= divider:
- i += 1
- bandwidth = bandwidth / divider
-
-print(f"{bandwidth:.1f}" + units[i] + "/s")
-
diff --git a/.config/ags/scripts/quickscripts/nixos-trim-generations.sh b/.config/ags/scripts/quickscripts/nixos-trim-generations.sh
deleted file mode 100755
index 98b59be95..000000000
--- a/.config/ags/scripts/quickscripts/nixos-trim-generations.sh
+++ /dev/null
@@ -1,243 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-## Defaults
-keepGensDef=30; keepDaysDef=30
-keepGens=$keepGensDef; keepDays=$keepDaysDef
-
-## Usage
-usage () {
- printf "Usage:\n\t ./trim-generations.sh \n\n
-(defaults are: Keep-Gens=$keepGensDef Keep-Days=$keepDaysDef Profile=user)\n\n"
- printf "If you enter any parameters, you must enter all three, or none to use defaults.\n"
- printf "Example:\n\t trim-generations.sh 15 10 home-manager\n"
- printf " this will work on the home-manager profile and keep all generations from the\n"
- printf "last 10 days, and keep at least 15 generations no matter how old.\n"
- printf "\nProfiles available are:\tuser, home-manager, channels, system (root)\n"
- printf "\n-h or --help prints this help text."
-}
-
-if [ $# -eq 1 ]; then # if help requested
- if [ $1 = "-h" ]; then
- usage
- exit 1;
- fi
- if [ $1 = "--help" ]; then
- usage
- exit 2;
- fi
- printf "Dont recognise your option exiting..\n\n"
- usage
- exit 3;
-
- elif [ $# -eq 0 ]; then # print the defaults
- printf "The current defaults are:\n Keep-Gens=$keepGensDef Keep-Days=$keepDaysDef \n\n"
- read -p "Keep these defaults? (y/n):" answer
-
- case "$answer" in
- [yY1] )
- printf "Using defaults..\n"
- ;;
- [nN0] ) printf "ok, doing nothing, exiting..\n"
- exit 6;
- ;;
- * ) printf "%b" "Doing nothing, exiting.."
- exit 7;
- ;;
- esac
-fi
-
-## Handle parameters (and change if root)
-if [[ $EUID -ne 0 ]]; then # if not root
- profile=$(readlink /home/$USER/.nix-profile)
-else
- if [ -d /nix/var/nix/profiles/system ]; then # maybe this or the other
- profile="/nix/var/nix/profiles/system"
- elif [ -d /nix/var/nix/profiles/default ]; then
- profile="/nix/var/nix/profiles/default"
- else
- echo "Cant find profile for root. Exiting"
- exit 8
- fi
-fi
-if (( $# < 1 )); then
- printf "Keeping default: $keepGensDef generations OR $keepDaysDef days, whichever is more\n"
-elif [[ $# -le 2 ]]; then
- printf "\nError: Not enough arguments.\n\n" >&2
- usage
- exit 1
-elif (( $# > 4)); then
- printf "\nError: Too many arguments.\n\n" >&2
- usage
- exit 2
-else
- if [ $1 -lt 1 ]; then
- printf "using Gen numbers less than 1 not recommended. Setting to min=1\n"
- read -p "is that ok? (y/n): " asnwer
- #printf "$asnwer"
- case "$asnwer" in
- [yY1] )
- printf "ok, continuing..\n"
- ;;
- [nN0] )
- printf "ok, doing nothing, exiting..\n"
- exit 6;
- ;;
- * )
- printf "%b" "Doing nothing, exiting.."
- exit 7;
- ;;
- esac
- fi
- if [ $2 -lt 0 ]; then
- printf "using negative days number not recommended. Setting to min=0\n"
- read -p "is that ok? (y/n): " asnwer
-
- case "$asnwer" in
- [yY1] )
- printf "ok, continuing..\n"
- ;;
- [nN0] )
- printf "ok, doing nothing, exiting..\n"
- exit 6;
- ;;
- * )
- printf "%b" "Doing nothing, exiting.."
- exit 7;
- ;;
- esac
- fi
- keepGens=$1; keepDays=$2;
- (( keepGens < 1 )) && keepGens=1
- (( keepDays < 0 )) && keepDays=0
- if [[ $EUID -ne 0 ]]; then
- if [[ $3 == "user" ]] || [[ $3 == "default" ]]; then
- profile=$(readlink /home/$USER/.nix-profile)
- elif [[ $3 == "home-manager" ]]; then
- # home-manager defaults to $XDG_STATE_HOME; otherwise, use
- # `home-manager generations` and `nix-store --query --roots
- # /nix/store/...` to figure out what reference is keeping the old
- # generations alive.
- profile="${XDG_STATE_HOME:-$HOME/.local/state}/nix/profiles/home-manager"
- elif [[ $3 == "channels" ]]; then
- profile="/nix/var/nix/profiles/per-user/$USER/channels"
- else
- printf "\nError: Do not understand your third argument. Should be one of: (user / home-manager/ channels)\n\n"
- usage
- exit 3
- fi
- else
- if [[ $3 == "system" ]]; then
- profile="/nix/var/nix/profiles/system"
- elif [[ $3 == "user" ]] || [[ $3 == "default" ]]; then
- profile="/nix/var/nix/profiles/default"
- else
- printf "\nError: Do not understand your third argument. Should be one of: (user / system)\n\n"
- usage
- exit 3
- fi
- fi
- printf "OK! \t Keep Gens = $keepGens \t Keep Days = $keepDays\n\n"
-fi
-
-printf "Operating on profile: \t $profile\n\n"
-
-## Runs at the end, to decide whether to delete profiles that match chosen parameters.
-choose () {
- local default="$1"
- local prompt="$2"
- local answer
-
- read -p "$prompt" answer
- [ -z "$answer" ] && answer="$default"
-
- case "$answer" in
- [yY1] ) #printf "answered yes!\n"
- nix-env --delete-generations -p $profile ${!gens[@]}
- exit 0
- ;;
- [nN0] ) printf "Ok doing nothing exiting..\n"
- exit 6;
- ;;
- * ) printf "%b" "Unexpected answer '$answer'!" >&2
- exit 7;
- ;;
- esac
-} # end of function choose
-
-# printf "profile = $profile\n\n"
-## Query nix-env for generations list
-IFS=$'\n' nixGens=( $(nix-env --list-generations -p $profile | sed 's:^\s*::; s:\s*$::' | tr '\t' ' ' | tr -s ' ') )
-timeNow=$(date +%s)
-
-## Get info on oldest generation
-IFS=' ' read -r -a oldestGenArr <<< "${nixGens[0]}"
-oldestGen=${oldestGenArr[0]}
-oldestDate=${oldestGenArr[1]}
-printf "%-30s %s\n" "oldest generation:" $oldestGen
-#oldestDate=${nixGens[0]:3:19}
-printf "%-30s %s\n" "oldest generation created:" $oldestDate
-oldestTime=$(date -d "$oldestDate" +%s)
-oldestElapsedSecs=$((timeNow-oldestTime))
-oldestElapsedMins=$((oldestElapsedSecs/60))
-oldestElapsedHours=$((oldestElapsedMins/60))
-oldestElapsedDays=$((oldestElapsedHours/24))
-printf "%-30s %s\n" "minutes before now:" $oldestElapsedMins
-printf "%-30s %s\n" "hours before now:" $oldestElapsedHours
-printf "%-30s %s\n\n" "days before now:" $oldestElapsedDays
-
-## Get info on current generation
-for i in "${nixGens[@]}"; do
- IFS=' ' read -r -a iGenArr <<< "$i"
- genNumber=${iGenArr[0]}
- genDate=${iGenArr[1]}
- if [[ "$i" =~ current ]]; then
- currentGen=$genNumber
- printf "%-30s %s\n" "current generation:" $currentGen
- currentDate=$genDate
- printf "%-30s %s\n" "current generation created:" $currentDate
- currentTime=$(date -d "$currentDate" +%s)
- currentElapsedSecs=$((timeNow-currentTime))
- currentElapsedMins=$((currentElapsedSecs/60))
- currentElapsedHours=$((currentElapsedMins/60))
- currentElapsedDays=$((currentElapsedHours/24))
- printf "%-30s %s\n" "minutes before now:" $currentElapsedMins
- printf "%-30s %s\n" "hours before now:" $currentElapsedHours
- printf "%-30s %s\n\n" "days before now:" $currentElapsedDays
- fi
-done
-
-## Compare oldest and current generations
-timeBetweenOldestAndCurrent=$((currentTime-oldestTime))
-elapsedDays=$((timeBetweenOldestAndCurrent/60/60/24))
-generationsDiff=$((currentGen-oldestGen))
-
-## Figure out what we should do, based on generations and options
-if [[ elapsedDays -le keepDays ]]; then
- printf "All generations are no more than $keepDays days older than current generation. \nOldest gen days difference from current gen: $elapsedDays \n\n\tNothing to do!\n"
- exit 4;
-elif [[ generationsDiff -lt keepGens ]]; then
- printf "Oldest generation ($oldestGen) is only $generationsDiff generations behind current ($currentGen). \n\n\t Nothing to do!\n"
- exit 5;
-else
- printf "\tSomething to do...\n"
- declare -a gens
- for i in "${nixGens[@]}"; do
- IFS=' ' read -r -a iGenArr <<< "$i"
- genNumber=${iGenArr[0]}
- genDiff=$((currentGen-genNumber))
- genDate=${iGenArr[1]}
- genTime=$(date -d "$genDate" +%s)
- elapsedSecs=$((timeNow-genTime))
- genDaysOld=$((elapsedSecs/60/60/24))
- if [[ genDaysOld -gt keepDays ]] && [[ genDiff -ge keepGens ]]; then
- gens["$genNumber"]="$genDate, $genDaysOld day(s) old"
- fi
- done
- printf "\nFound the following generation(s) to delete:\n"
- for K in "${!gens[@]}"; do
- printf "generation $K \t ${gens[$K]}\n"
- done
- printf "\n"
- choose "y" "Do you want to delete these? [Y/n]: "
-fi
diff --git a/.config/ags/scripts/sway/swayToRelativeWs.sh b/.config/ags/scripts/sway/swayToRelativeWs.sh
deleted file mode 100755
index 81e887b79..000000000
--- a/.config/ags/scripts/sway/swayToRelativeWs.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/env bash
-
-# Check if sway is running
-if ! pgrep -x sway > /dev/null; then
- echo "Sway is not running"
- exit 1
-fi
-
-
-# Get the current workspace number
-current=$(swaymsg -t get_workspaces | jq '.[] | select(.focused==true) | .num')
-
-# Check if a number was passed as an argument
-if [[ "$1" =~ ^[+-]?[0-9]+$ ]]; then
- new_workspace=$((current + $1))
-else
- new_workspace=$((current + 1))
-fi
-
-# Check if the new workspace number is out of bounds
-if [[ $new_workspace -lt 1 ]]; then
- exit 0
-fi
-
-# Switch to the new workspace
-if [[ $2 == 'move' ]]; then
- swaymsg move container to workspace $new_workspace
-else
- swaymsg workspace $new_workspace
-fi
diff --git a/.config/ags/scripts/templates/ags/sourceviewtheme-light.xml b/.config/ags/scripts/templates/ags/sourceviewtheme-light.xml
deleted file mode 100644
index eca04bf3b..000000000
--- a/.config/ags/scripts/templates/ags/sourceviewtheme-light.xml
+++ /dev/null
@@ -1,95 +0,0 @@
-
-
- end_4
- <_description>Catppuccin port but very random
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.config/ags/scripts/templates/ags/sourceviewtheme.xml b/.config/ags/scripts/templates/ags/sourceviewtheme.xml
deleted file mode 100644
index e2e5fe9a4..000000000
--- a/.config/ags/scripts/templates/ags/sourceviewtheme.xml
+++ /dev/null
@@ -1,121 +0,0 @@
-
-
-
-
-
-
- Leo Iannacone
- <_description>Based on SublimeText Monokai Extended - Generated with tm2gtksw2
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.config/ags/scripts/templates/fuzzel/fuzzel.ini b/.config/ags/scripts/templates/fuzzel/fuzzel.ini
deleted file mode 100644
index 0dc348942..000000000
--- a/.config/ags/scripts/templates/fuzzel/fuzzel.ini
+++ /dev/null
@@ -1,21 +0,0 @@
-font=Gabarito
-terminal=kitty -1
-prompt=">> "
-layer=overlay
-
-[colors]
-background={{ $background }}ff
-text={{ $onBackground }}ff
-selection={{ $surfaceVariant }}ff
-selection-text={{ $onSurfaceVariant }}ff
-border={{ $surfaceVariant }}dd
-match={{ $primary }}ff
-selection-match={{ $primary }}ff
-
-
-[border]
-radius=17
-width=1
-
-[dmenu]
-exit-immediately-if-empty=yes
diff --git a/.config/ags/scripts/templates/gradience/preset.json b/.config/ags/scripts/templates/gradience/preset.json
deleted file mode 100644
index aeb57489c..000000000
--- a/.config/ags/scripts/templates/gradience/preset.json
+++ /dev/null
@@ -1,144 +0,0 @@
-{
- "name": "Material3_Generated",
- "variables": {
- "theme_fg_color": "#AEE5FA",
- "theme_text_color": "#AEE5FA",
- "theme_bg_color": "#1a1b26",
- "theme_base_color": "#1a1b26",
- "theme_selected_bg_color": "#AEE5FA",
- "theme_selected_fg_color": "rgba(0, 0, 0, 0.87)",
- "insensitive_bg_color": "#1a1b26",
- "insensitive_fg_color": "rgba(192, 202, 245, 0.5)",
- "insensitive_base_color": "#24283b",
- "theme_unfocused_fg_color": "#AEE5FA",
- "theme_unfocused_text_color": "#c0caf5",
- "theme_unfocused_bg_color": "#1a1b26",
- "theme_unfocused_base_color": "#1a1b26",
- "theme_unfocused_selected_bg_color": "#a9b1d6",
- "theme_unfocused_selected_fg_color": "rgba(0, 0, 0, 0.87)",
- "unfocused_insensitive_color": "rgba(192, 202, 245, 0.5)",
- "borders": "rgba(192, 202, 245, 0.12)",
- "unfocused_borders": "rgba(192, 202, 245, 0.12)",
- "warning_color": "#FDD633",
- "error_color": "#BA1B1B",
- "success_color": "#81C995",
- "wm_title": "#AEE5FA",
- "wm_unfocused_title": "rgba(192, 202, 245, 0.7)",
- "wm_highlight": "rgba(192, 202, 245, 0.1)",
- "wm_bg": "#1a1b26",
- "wm_unfocused_bg": "#1a1b26",
- "wm_button_close_icon": "#1a1b26",
- "wm_button_close_hover_bg": "#a9b1d6",
- "wm_button_close_active_bg": "#c7c7c7",
- "content_view_bg": "#1a1b26",
- "placeholder_text_color": "silver",
- "text_view_bg": "#1d1d1d",
- "budgie_tasklist_indicator_color": "#90D1F6",
- "budgie_tasklist_indicator_color_active": "#90D1F6",
- "budgie_tasklist_indicator_color_active_window": "#999999",
- "budgie_tasklist_indicator_color_attention": "#FDD633",
- "STRAWBERRY_100": "#FF9262",
- "STRAWBERRY_300": "#FF793E",
- "STRAWBERRY_500": "#F15D22",
- "STRAWBERRY_700": "#CF3B00",
- "STRAWBERRY_900": "#AC1800",
- "ORANGE_100": "#FFDB91",
- "ORANGE_300": "#FFCA40",
- "ORANGE_500": "#FAA41A",
- "ORANGE_700": "#DE8800",
- "ORANGE_900": "#C26C00",
- "BANANA_100": "#FFFFA8",
- "BANANA_300": "#FFFA7D",
- "BANANA_500": "#FFCE51",
- "BANANA_700": "#D1A023",
- "BANANA_900": "#A27100",
- "LIME_100": "#A2F3BE",
- "LIME_300": "#8ADBA6",
- "LIME_500": "#73C48F",
- "LIME_700": "#479863",
- "LIME_900": "#1C6D38",
- "BLUEBERRY_100": "#94A6FF",
- "BLUEBERRY_300": "#6A7CE0",
- "BLUEBERRY_500": "#3F51B5",
- "BLUEBERRY_700": "#213397",
- "BLUEBERRY_900": "#031579",
- "GRAPE_100": "#D25DE6",
- "GRAPE_300": "#B84ACB",
- "GRAPE_500": "#9C27B0",
- "GRAPE_700": "#830E97",
- "GRAPE_900": "#6A007E",
- "COCOA_100": "#9F9792",
- "COCOA_300": "#7B736E",
- "COCOA_500": "#574F4A",
- "COCOA_700": "#463E39",
- "COCOA_900": "#342C27",
- "SILVER_100": "#EEE",
- "SILVER_300": "#CCC",
- "SILVER_500": "#AAA",
- "SILVER_700": "#888",
- "SILVER_900": "#666",
- "SLATE_100": "#888",
- "SLATE_300": "#666",
- "SLATE_500": "#444",
- "SLATE_700": "#222",
- "SLATE_900": "#111",
- "BLACK_100": "#474341",
- "BLACK_300": "#403C3A",
- "BLACK_500": "#393634",
- "BLACK_700": "#33302F",
- "BLACK_900": "#2B2928",
- "accent_bg_color": "{{ $primary }}",
- "accent_fg_color": "{{ $onPrimary }}",
- "accent_color": "{{ $primary }}",
- "destructive_bg_color": "{{ $error }}",
- "destructive_fg_color": "{{ $onError }}",
- "destructive_color": "{{ $error }}",
- "success_bg_color": "#81C995",
- "success_fg_color": "rgba(0, 0, 0, 0.87)",
- "warning_bg_color": "#FDD633",
- "warning_fg_color": "rgba(0, 0, 0, 0.87)",
- "error_bg_color": "{{ $error }}",
- "error_fg_color": "{{ $onError }}",
- "window_bg_color": "{{ $background }}",
- "window_fg_color": "{{ $onBackground }}",
- "view_bg_color": "{{ $surface }}",
- "view_fg_color": "{{ $onSurface }}",
- "headerbar_bg_color": "mix(@dialog_bg_color, @window_bg_color, 0.5)",
- "headerbar_fg_color": "{{ $onSecondaryContainer }}",
- "headerbar_border_color": "{{ $secondaryContainer }}",
- "headerbar_backdrop_color": "@headerbar_bg_color",
- "headerbar_shade_color": "rgba(0, 0, 0, 0.09)",
- "card_bg_color": "{{ $background }}",
- "card_fg_color": "{{ $onSecondaryContainer }}",
- "card_shade_color": "rgba(0, 0, 0, 0.09)",
- "dialog_bg_color": "{{ $secondaryContainer }}",
- "dialog_fg_color": "{{ $onSecondaryContainer }}",
- "popover_bg_color": "{{ $secondaryContainer }}",
- "popover_fg_color": "{{ $onSecondaryContainer }}",
- "thumbnail_bg_color": "#1a1b26",
- "thumbnail_fg_color": "#AEE5FA",
- "shade_color": "rgba(0, 0, 0, 0.36)",
- "scrollbar_outline_color": "rgba(0, 0, 0, 0.5)",
-
- "sidebar_bg_color": "@window_bg_color",
- "sidebar_fg_color":"@window_fg_color",
- "sidebar_border_color": "@sidebar_bg_color",
- "sidebar_backdrop_color": "@sidebar_bg_color"
- },
- "palette": {
- "blue_": {},
- "green_": {},
- "yellow_": {},
- "orange_": {},
- "red_": {},
- "purple_": {},
- "brown_": {},
- "light_": {},
- "dark_": {}
- },
- "custom_css": {
- "gtk4": "",
- "gtk3": ""
- },
- "plugins": {}
-}
\ No newline at end of file
diff --git a/.config/ags/scripts/templates/gtk/gtk-colors.css b/.config/ags/scripts/templates/gtk/gtk-colors.css
deleted file mode 100644
index b8ed1a4c7..000000000
--- a/.config/ags/scripts/templates/gtk/gtk-colors.css
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
-* GTK Colors
-*/
-
-@define-color accent_color {{ $primary }};
-@define-color accent_fg_color {{ $onPrimary }};
-@define-color accent_bg_color {{ $primary }};
-@define-color window_bg_color {{ $background }};
-@define-color window_fg_color {{ $onBackground }};
-@define-color headerbar_bg_color {{ $surfaceDim }};
-@define-color headerbar_fg_color {{ $onSurface }};
-@define-color popover_bg_color {{ $surfaceDim }};
-@define-color popover_fg_color {{ $onSurface }};
-@define-color view_bg_color {{ $surface }};
-@define-color view_fg_color {{ $onSurface }};
-@define-color card_bg_color {{ $surface }};
-@define-color card_fg_color {{ $onSurface }};
-@define-color sidebar_bg_color @window_bg_color;
-@define-color sidebar_fg_color @window_fg_color;
-@define-color sidebar_border_color @window_bg_color;
-@define-color sidebar_backdrop_color @window_bg_color;
diff --git a/.config/ags/scripts/templates/hypr/hyprland/colors.conf b/.config/ags/scripts/templates/hypr/hyprland/colors.conf
deleted file mode 100644
index 8c0689f31..000000000
--- a/.config/ags/scripts/templates/hypr/hyprland/colors.conf
+++ /dev/null
@@ -1,34 +0,0 @@
-# exec = export SLURP_ARGS='-d -c {{ $onSecondaryContainer }}BB -b {{ $secondaryContainer }}44 -s 00000000'
-
-general {
- col.active_border = rgba({{ $onSurface }}39)
- col.inactive_border = rgba({{ $outline }}30)
-}
-
-misc {
- background_color = rgba({{ $surface }}FF)
-}
-
-plugin {
- hyprbars {
- # Honestly idk if it works like css, but well, why not
- bar_text_font = Rubik, Geist, AR One Sans, Reddit Sans, Inter, Roboto, Ubuntu, Noto Sans, sans-serif
- bar_height = 30
- bar_padding = 10
- bar_button_padding = 5
- bar_precedence_over_border = true
- bar_part_of_window = true
-
- bar_color = rgba({{ $background }}FF)
- col.text = rgba({{ $onBackground }}FF)
-
-
- # example buttons (R -> L)
- # hyprbars-button = color, size, on-click
- hyprbars-button = rgb({{ $onBackground }}), 13, , hyprctl dispatch killactive
- hyprbars-button = rgb({{ $onBackground }}), 13, , hyprctl dispatch fullscreen 1
- hyprbars-button = rgb({{ $onBackground }}), 13, , hyprctl dispatch movetoworkspacesilent special
- }
-}
-
-windowrulev2 = bordercolor rgba({{ $primary }}AA) rgba({{ $primary }}77),pinned:1
\ No newline at end of file
diff --git a/.config/ags/scripts/templates/hypr/hyprlock.conf b/.config/ags/scripts/templates/hypr/hyprlock.conf
deleted file mode 100644
index 41342ef35..000000000
--- a/.config/ags/scripts/templates/hypr/hyprlock.conf
+++ /dev/null
@@ -1,94 +0,0 @@
-$text_color = rgba({{ $primaryFixed }}FF)
-$entry_background_color = rgba({{ $onPrimaryFixed }}11)
-$entry_border_color = rgba({{ $outline }}55)
-$entry_color = rgba({{ $primaryFixed }}FF)
-$font_family = Rubik Light
-$font_family_clock = Rubik Light
-$font_material_symbols = Material Symbols Rounded
-
-background {
- color = rgba(181818FF)
- # path = {{ SWWW_WALL }}
-
- # path = screenshot
- # blur_size = 15
- # blur_passes = 4
-}
-input-field {
- monitor =
- size = 250, 50
- outline_thickness = 2
- dots_size = 0.1
- dots_spacing = 0.3
- outer_color = $entry_border_color
- inner_color = $entry_background_color
- font_color = $entry_color
- fade_on_empty = true
-
- position = 0, 20
- halign = center
- valign = center
-}
-
-label { # Caps Lock Warning
- monitor =
- text = cmd[update:250] ${XDG_CONFIG_HOME:-$HOME/.config}/hypr/hyprlock/check-capslock.sh
- color = $text_color
- font_size = 13
- font_family = $font_family
- position = 0, -25
- halign = center
- valign = center
-}
-
-label { # Clock
- monitor =
- text = $TIME
- color = $text_color
- font_size = 65
- font_family = $font_family_clock
-
- position = 0, 300
- halign = center
- valign = center
-}
-label { # Date
- monitor =
- text = cmd[update:5000] date +"%A, %B %d"
- color = $text_color
- font_size = 17
- font_family = $font_family
-
- position = 0, 240
- halign = center
- valign = center
-}
-
-label { # User
- monitor =
- text = $USER
- color = $text_color
- shadow_passes = 1
- shadow_boost = 0.35
- outline_thickness = 2
- dots_size = 0.2 # Scale of input-field height, 0.2 - 0.8
- dots_spacing = 0.2 # Scale of dots' absolute size, 0.0 - 1.0
- dots_center = true
- font_size = 20
- font_family = $font_family
- position = 0, 50
- halign = center
- valign = bottom
-}
-
-label { # Status
- monitor =
- text = cmd[update:5000] ${XDG_CONFIG_HOME:-$HOME/.config}/hypr/hyprlock/status.sh
- color = $text_color
- font_size = 14
- font_family = $font_family
-
- position = 30, -30
- halign = left
- valign = top
-}
\ No newline at end of file
diff --git a/.config/ags/scripts/templates/terminal/scheme-base.json b/.config/ags/scripts/templates/terminal/scheme-base.json
deleted file mode 100644
index e4b78e7e7..000000000
--- a/.config/ags/scripts/templates/terminal/scheme-base.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "dark": {
- "term0" : "#282828",
- "term1" : "#CC241D",
- "term2" : "#98971A",
- "term3" : "#D79921",
- "term4" : "#458588",
- "term5" : "#B16286",
- "term6" : "#689D6A",
- "term7" : "#A89984",
- "term8" : "#928374",
- "term9" : "#FB4934",
- "term10" : "#B8BB26",
- "term11" : "#FABD2F",
- "term12" : "#83A598",
- "term13" : "#D3869B",
- "term14" : "#8EC07C",
- "term15" : "#EBDBB2"
- },
- "light": {
- "term0" : "#FDF9F3",
- "term1" : "#FF6188",
- "term2" : "#A9DC76",
- "term3" : "#FC9867",
- "term4" : "#FFD866",
- "term5" : "#F47FD4",
- "term6" : "#78DCE8",
- "term7" : "#333034",
- "term8" : "#121212",
- "term9" : "#FF6188",
- "term10" : "#A9DC76",
- "term11" : "#FC9867",
- "term12" : "#FFD866",
- "term13" : "#F47FD4",
- "term14" : "#78DCE8",
- "term15" : "#333034"
- }
-}
diff --git a/.config/ags/scripts/templates/terminal/scheme-monochrome.json b/.config/ags/scripts/templates/terminal/scheme-monochrome.json
deleted file mode 100644
index 5807a26e4..000000000
--- a/.config/ags/scripts/templates/terminal/scheme-monochrome.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "dark": {
- "term0": "#000000",
- "term1": "#FFFFFF",
- "term2": "#CCCCCC",
- "term3": "#8f8f8f",
- "term4": "#FFFFFF",
- "term5": "#111111",
- "term6": "#CCCCCC",
- "term7": "#FFFFFF",
- "term8": "#404040",
- "term9": "#CCCCCC",
- "term10": "#FFFFFF",
- "term11": "#909090",
- "term12": "#CCCCCC",
- "term13": "#808080",
- "term14": "#CCCCCC",
- "term15": "#FFFFFF"
- },
- "light": {
- "term0": "#EAE9EA",
- "term1": "#777777",
- "term2": "#000000",
- "term3": "#000000",
- "term4": "#000000",
- "term5": "#000000",
- "term6": "#000000",
- "term7": "#202020",
- "term8": "#000000",
- "term9": "#000000",
- "term10": "#CCCCCC",
- "term11": "#808080",
- "term12": "#CCCCCC",
- "term13": "#FFFFFF"
- }
-}
diff --git a/.config/ags/scripts/templates/terminal/sequences.txt b/.config/ags/scripts/templates/terminal/sequences.txt
deleted file mode 100644
index 40575f546..000000000
--- a/.config/ags/scripts/templates/terminal/sequences.txt
+++ /dev/null
@@ -1 +0,0 @@
-]4;0;#$term0 #\]1;0;#$term0 #\]4;1;#$term1 #\]4;2;#$term2 #\]4;3;#$term3 #\]4;4;#$term4 #\]4;5;#$term5 #\]4;6;#$term6 #\]4;7;#$term7 #\]4;8;#$term8 #\]4;9;#$term9 #\]4;10;#$term10 #\]4;11;#$term11 #\]4;12;#$term12 #\]4;13;#$term13 #\]4;14;#$term14 #\]4;15;#$term15 #\]10;#$term7 #\]11;[$alpha]#$term0 #\]12;#$term7 #\]13;#$term7 #\]17;#$term7 #\]19;#$term0 #\]4;232;#$term7 #\]4;256;#$term7 #\]708;[$alpha]#$term0 #\]11;#$term0 #\
diff --git a/.config/ags/scripts/templates/wal/_musicwal.scss b/.config/ags/scripts/templates/wal/_musicwal.scss
deleted file mode 100644
index cad4df3f5..000000000
--- a/.config/ags/scripts/templates/wal/_musicwal.scss
+++ /dev/null
@@ -1,22 +0,0 @@
-// Special
-$background: {{backgroundColor}};
-$foreground: {{foregroundColor}};
-$cursor: {{foregroundColor}};
-
-// Colors
-$color0: {{dominantColor}};
-$color1: {{dominantColor}};
-$color2: {{dominantColor}};
-$color3: {{dominantColor}};
-$color4: {{dominantColor}};
-$color5: {{dominantColor}};
-$color6: {{dominantColor}};
-$color7: {{dominantColor}};
-$color8: {{dominantColor}};
-$color9: {{dominantColor}};
-$color10: {{dominantColor}};
-$color11: {{dominantColor}};
-$color12: {{dominantColor}};
-$color13: {{dominantColor}};
-$color14: {{dominantColor}};
-$color15: {{dominantColor}};
\ No newline at end of file
diff --git a/.config/ags/scripts/wayland-idle-inhibitor.py b/.config/ags/scripts/wayland-idle-inhibitor.py
deleted file mode 100755
index ec74d09b1..000000000
--- a/.config/ags/scripts/wayland-idle-inhibitor.py
+++ /dev/null
@@ -1,82 +0,0 @@
-#!/usr/bin/env -S\_/bin/sh\_-xc\_"source\_\$(eval\_echo\_\$ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate&&exec\_python\_-E\_"\$0"\_"\$@""
-import sys
-from dataclasses import dataclass
-from signal import SIGINT, SIGTERM, signal
-from threading import Event
-import setproctitle
-
-from pywayland.client.display import Display
-from pywayland.protocol.idle_inhibit_unstable_v1.zwp_idle_inhibit_manager_v1 import (
- ZwpIdleInhibitManagerV1,
-)
-from pywayland.protocol.wayland.wl_compositor import WlCompositor
-from pywayland.protocol.wayland.wl_registry import WlRegistryProxy
-from pywayland.protocol.wayland.wl_surface import WlSurface
-
-
-@dataclass
-class GlobalRegistry:
- surface: WlSurface | None = None
- inhibit_manager: ZwpIdleInhibitManagerV1 | None = None
-
-
-def handle_registry_global(
- wl_registry: WlRegistryProxy, id_num: int, iface_name: str, version: int
-) -> None:
- global_registry: GlobalRegistry = wl_registry.user_data or GlobalRegistry()
-
- if iface_name == "wl_compositor":
- compositor = wl_registry.bind(id_num, WlCompositor, version)
- global_registry.surface = compositor.create_surface() # type: ignore
- elif iface_name == "zwp_idle_inhibit_manager_v1":
- global_registry.inhibit_manager = wl_registry.bind(
- id_num, ZwpIdleInhibitManagerV1, version
- )
-
-
-def main() -> None:
- done = Event()
- signal(SIGINT, lambda _, __: done.set())
- signal(SIGTERM, lambda _, __: done.set())
-
- global_registry = GlobalRegistry()
-
- display = Display()
- display.connect()
-
- registry = display.get_registry() # type: ignore
- registry.user_data = global_registry
- registry.dispatcher["global"] = handle_registry_global
-
- def shutdown() -> None:
- display.dispatch()
- display.roundtrip()
- display.disconnect()
-
- display.dispatch()
- display.roundtrip()
-
- if global_registry.surface is None or global_registry.inhibit_manager is None:
- print("Wayland seems not to support idle_inhibit_unstable_v1 protocol.")
- shutdown()
- sys.exit(1)
-
- inhibitor = global_registry.inhibit_manager.create_inhibitor( # type: ignore
- global_registry.surface
- )
-
- display.dispatch()
- display.roundtrip()
-
- print("Inhibiting idle...")
- done.wait()
- print("Shutting down...")
-
- inhibitor.destroy()
-
- shutdown()
-
-
-if __name__ == "__main__":
- setproctitle.setproctitle("wayland-idle-inhibitor.py")
- main()
diff --git a/.config/ags/scss/_bar.scss b/.config/ags/scss/_bar.scss
deleted file mode 100644
index 248f1fbc6..000000000
--- a/.config/ags/scss/_bar.scss
+++ /dev/null
@@ -1,437 +0,0 @@
-// Made to be pixel-perfect with 11pt font size
-// 1rem = 11pt = 14.6666666667px
-$bar_ws_width: 1.774rem;
-$bar_ws_width_focus: 0.614rem;
-$bar_ws_width_focus_active: 2.045rem;
-
-@mixin bar-group-rounding {
- @include small-rounding;
-}
-
-.bar-height {
- min-height: 2.727rem;
-}
-
-.bar-bg {
- background-color: $layer0;
- min-height: 2.727rem;
-}
-
-.bar-bg-focus {
- background-color: $layer0;
- min-height: 1.364rem;
-}
-
-.bar-bg-nothing {
- background-color: $layer0;
- min-height: 2px;
-}
-
-.bar-bg-focus-batterylow {
- background-color: mix($layer0, $errorContainer, 80%);
-}
-
-.bar-sidespace {
- min-width: 1.5rem;
-}
-
-.bar-group-margin {
- padding: 0.273rem 0rem;
-}
-
-.bar-group {
- background-color: $layer1;
-}
-
-.bar-group-borderless {
- background-color: transparent;
-}
-
-.bar-group-pad {
- padding: 0.205rem;
-}
-
-.bar-group-pad-less {
- padding: 0rem 0.681rem;
-}
-
-.bar-group-pad-system {
- padding: 0rem 0.341rem;
-}
-
-.bar-group-pad-music {
- padding-right: 1.023rem;
- padding-left: 0.341rem;
-}
-
-.bar-group-standalone {
- @include bar-group-rounding;
- -gtk-outline-radius: 1.364rem;
-}
-
-.bar-group-round {
- border-radius: 10rem;
- -gtk-outline-radius: 10rem;
-}
-
-.bar-group-middle {
- border-radius: 0.477rem;
- -gtk-outline-radius: 0.477rem;
-}
-
-.bar-group-left {
- border-radius: 0.477rem;
- -gtk-outline-radius: 0.477rem;
- border-top-left-radius: 1.364rem;
- border-bottom-left-radius: 1.364rem;
-}
-
-.bar-group-right {
- border-radius: 0.477rem;
- -gtk-outline-radius: 0.477rem;
- border-top-right-radius: 1.364rem;
- border-bottom-right-radius: 1.364rem;
-}
-
-.bar-sidemodule {
- min-width: 26rem;
-}
-
-.bar-ws-width {
- min-width: 18.341rem;
-}
-
-
-.bar-ws-container {
- transition: 700ms cubic-bezier(0.1, 1, 0, 1);
-}
-
-.bar-ws {
- font-size: 1.02rem;
- font-weight: 600;
- min-width: $bar_ws_width;
- color: $workspaceOnLayer1Inactive;
-}
-
-.bar-ws-active {
- background-color: $workspaceLayer3;
- color: $workspaceOnLayer3;
-}
-
-.bar-ws-occupied {
- background-color: $layer2;
- color: $workspaceOnLayer2;
-}
-
-// Focus is the bar mode name, not the workspace state!
-
-.bar-ws-focus {
- background-color: $surfaceVariant;
- min-width: $bar_ws_width_focus;
-}
-
-.bar-ws-focus-active {
- min-width: $bar_ws_width_focus_active;
- background-color: $onLayer0;
-}
-
-.bar-ws-focus-occupied {
- background-color: $secondaryContainer;
-}
-
-.bar-clock-box {
- margin: 0rem 0.682rem;
-}
-
-.bar-time {
- @include titlefont;
- font-size: 1.2727rem;
- color: $timeOnLayer1;
-}
-
-.bar-date {
- color: $dateOnLayer1;
-}
-
-.bar-batt {
- @include full-rounding;
- @include element_decel;
- min-height: 1.77rem;
- min-width: 1.77rem;
- border-radius: 10rem;
- color: $battOnLayer2;
-}
-
-.bar-batt-txt {
- color: $battOnLayer1;
-}
-
-.bar-batt-circprog {
- @include fluent_decel_long;
- min-width: 0.136rem; // line width
- min-height: 1.636rem;
- padding: 0rem;
- background-color: $battLayer2;
- color: $battOnLayer2;
-}
-
-.bar-batt-circprog-borderless {
- background-color: transparent;
-}
-
-.bar-batt-circprog-low {
- background-color: $error;
- color: $errorContainer;
-}
-
-
-.bar-batt-low {
- background-color: $error;
- color: $errorContainer;
-}
-
-.bar-ram-icon {
- @include full-rounding;
- @include element_decel;
- min-height: 1.77rem;
- min-width: 1.77rem;
- border-radius: 10rem;
- color: $ramOnLayer2;
-}
-
-.bar-ram-circprog {
- @include fluent_decel_long;
- min-width: 0.136rem; // line width
- min-height: 1.636rem;
- padding: 0rem;
- background-color: $ramLayer2;
- color: $ramOnLayer2;
-}
-
-.bar-ram-circprog-borderless {
- background-color: transparent;
-}
-
-.bar-ram-txt {
- color: $ramOnLayer1;
-}
-
-.bar-swap-icon {
- @include full-rounding;
- @include element_decel;
- min-height: 1.77rem;
- min-width: 1.77rem;
- border-radius: 10rem;
- color: $swapOnLayer2;
-}
-
-.bar-swap-circprog {
- @include fluent_decel_long;
- min-width: 0.136rem; // line width
- min-height: 1.636rem;
- padding: 0rem;
- background-color: $swapLayer2;
- color: $swapOnLayer2;
-}
-
-.bar-swap-circprog-borderless {
- background-color: transparent;
-}
-
-.bar-swap-txt {
- color: $swapOnLayer1;
-}
-
-.bar-cpu-icon {
- @include full-rounding;
- @include element_decel;
- min-height: 1.77rem;
- min-width: 1.77rem;
- border-radius: 10rem;
- color: $cpuOnLayer2;
-}
-
-.bar-cpu-circprog {
- @include fluent_decel_long;
- min-width: 0.136rem; // line width
- min-height: 1.636rem;
- padding: 0rem;
- background-color: $cpuLayer2;
- color: $cpuOnLayer2;
-}
-
-.bar-cpu-circprog-borderless {
- background-color: transparent;
-}
-
-.bar-cpu-txt {
- color: $cpuOnLayer1;
-}
-
-.bar-music-playstate {
- @include element_decel;
- min-height: 1.77rem;
- min-width: 1.77rem;
- border-radius: 10rem;
- color: $musicOnLayer2;
-}
-
-.bar-music-circprog {
- @include fluent_decel_long;
- min-width: 0.136rem; // line width
- min-height: 1.636rem;
- padding: 0rem;
- background-color: $musicLayer2;
- color: $musicOnLayer2;
-}
-
-.bar-music-circprog-borderless {
- background-color: transparent;
-}
-
-.bar-music-playstate-playing {
- min-height: 1.77rem;
- min-width: 1.77rem;
- border-radius: 10rem;
- color: $musicOnLayer2;
-}
-
-.bar-music-playstate-txt {
- transition: 100ms cubic-bezier(0.05, 0.7, 0.1, 1);
- @include icon-material;
-}
-
-.bar-music-txt {
- color: $musicOnLayer1;
-}
-
-.bar-music-cover {
- background-position: center;
- background-repeat: no-repeat;
- background-size: 100% auto;
- min-width: 11.932rem;
-}
-
-.bar-music-extended-bg {
- border-radius: 1.364rem;
- min-width: 34.091rem;
-}
-
-.bar-music-hide-false {
- @include menu_decel;
- transition-duration: 100ms;
- opacity: 1;
-}
-
-.bar-music-hide-true {
- @include menu_accel;
- transition-duration: 100ms;
- opacity: 0;
-}
-
-.bar-corner-spacing {
- min-width: $rounding_large;
- min-height: $rounding_large;
-}
-
-.corner {
- background-color: $layer0;
- @include large-rounding;
-}
-
-.corner-black {
- background-color: $black; // Hard code: fake screen corner
- @include large-rounding;
-}
-
-.bar-wintitle-topdesc {
- margin-top: -0.136rem;
- margin-bottom: -0.341rem;
- color: $windowtitleOnLayer0Inactive;
-}
-
-.bar-wintitle-txt {
- color: $windowtitleOnLayer0;
-}
-
-.bar-space-button {
- padding: 0.341rem;
-}
-
-.bar-space-button>box:first-child {
- @include full-rounding;
- padding: 0rem 0.682rem;
-}
-
-.bar-space-button-leftmost {
- box {
- margin: 0rem 0.682rem;
- }
-}
-
-.bar-space-area-rightmost>box {
- padding-right: 2.386rem;
-}
-
-.bar-systray {
- @include full-rounding;
- margin: 0.137rem 0rem;
- padding: 0rem 0.682rem;
-}
-
-.bar-systray-item {
- @include full-rounding;
- @include element_decel;
- @include symbolic-icon;
- min-height: 1.032rem;
- min-width: 1.032rem;
- font-size: 1.032rem;
- color: $trayOnLayer0;
-}
-
-.bar-statusicons {
- @include full-rounding;
- @include element_decel;
- margin: 0.273rem;
- padding: 0rem 0.614rem;
-}
-
-.bar-statusicons-active {
- background-color: $layer0Active;
- color: $onLayer0Active;
-}
-
-.bar-util-btn {
- @include full-rounding;
- @include element_decel;
- min-height: 1.77rem;
- min-width: 1.77rem;
- background-color: $utilsLayer2;
- color: $utilsOnLayer2;
-}
-
-.bar-util-btn-borderless {
- background-color: transparent;
-}
-
-.bar-util-btn:hover,
-.bar-util-btn:focus {
- background-color: $layer2Hover;
-}
-
-.bar-util-btn:active {
- background-color: $layer2Active;
-}
-
-.bar-spaceright {
- color: $barspacerightOnLayer0;
-}
-
-.bar-bluetooth-device {
- @include full-rounding;
- @include symbolic-icon;
- min-height: 1.032rem;
- min-width: 1.032rem;
- font-size: 1.032rem;
- padding: 0.205rem 0.341rem;
-}
diff --git a/.config/ags/scss/_cheatsheet.scss b/.config/ags/scss/_cheatsheet.scss
deleted file mode 100644
index 19c0c9761..000000000
--- a/.config/ags/scss/_cheatsheet.scss
+++ /dev/null
@@ -1,168 +0,0 @@
-.cheatsheet-bg {
- @include large-rounding;
- @include elevation-border;
- @include elevation2;
- margin-bottom: 0.682rem;
- background-color: $layer0;
- padding: 1.364rem;
-}
-
-.cheatsheet-title {
- color: $cheatsheetTitle;
-}
-
-.cheatsheet-bind-lineheight {
- min-height: 2.045rem;
-}
-
-.cheatsheet-key {
- @include techfont;
- min-height: 1.364rem;
- min-width: 1.364rem;
- margin: 0.17rem;
- padding: 0.136rem 0.205rem;
- -gtk-outline-radius: 0.409rem;
- color: $cheatsheetTitle;
- border-radius: 0.409rem;
- border: 0.068rem solid $cheatsheetTitle;
- box-shadow: 0rem 0.136rem 0rem $cheatsheetTitle;
-}
-
-.cheatsheet-key-notkey {
- min-height: 1.364rem;
- padding: 0.136rem 0.205rem;
- margin: 0.17rem;
- color: $onLayer0;
-}
-
-@for $i from 1 through 8 {
- .cheatsheet-color-#{$i} {
- color: nth($cheatsheetColors, $i);
- border-color: nth($cheatsheetColors, $i);
- box-shadow: 0rem 0.136rem 0rem nth($cheatsheetColors, $i);
- }
-}
-
-// .cheatsheet-action {}
-
-.cheatsheet-closebtn {
- @include element_decel;
- @include full-rounding;
- min-width: 2.386rem;
- min-height: 2.386rem;
-}
-
-.cheatsheet-closebtn:hover,
-.cheatsheet-closebtn:focus {
- background-color: $layer0Hover;
-}
-
-.cheatsheet-closebtn:active {
- background-color: $layer0Active;
-}
-
-.cheatsheet-category-title {
- @include titlefont;
- font-size: 1.705rem;
-}
-
-@mixin cheatsheet-periodictable-element {
- min-width: 5.455rem;
- min-height: 5.455rem;
- @include small-rounding;
- background-color: $layer1;
- color: $onLayer1;
-}
-
-.cheatsheet-periodictable-elementsymbol {
- @include readingfont;
- font-size: 1.705rem;
- font-weight: bold;
-}
-
-.cheatsheet-periodictable-elementnum {
- @include full-rounding;
- min-width: 1.364rem;
- min-height: 1.364rem;
- background-color: $term0;
- color: $onBackground;
-}
-
-$colormetal: $term2;
-$colornonmetal: $term4;
-$colornoblegas: $term5;
-$colorlanthanum: $term3;
-$coloractinium: $term7;
-
-.cheatsheet-periodictable-empty {
- @include small-rounding;
- min-width: 5.455rem;
- min-height: 5.455rem;
-}
-
-.cheatsheet-periodictable-metal {
- @include cheatsheet-periodictable-element;
- background-color: $colormetal;
- color: $term0;
-}
-
-.cheatsheet-periodictable-nonmetal {
- @include cheatsheet-periodictable-element;
- background-color: $colornonmetal;
- color: $term0;
-}
-
-.cheatsheet-periodictable-noblegas {
- @include cheatsheet-periodictable-element;
- background-color: $colornoblegas;
- color: $term0;
-}
-
-.cheatsheet-periodictable-lanthanum {
- @include cheatsheet-periodictable-element;
- background-color: $colorlanthanum;
- color: $term0;
-}
-
-.cheatsheet-periodictable-actinium {
- @include cheatsheet-periodictable-element;
- background-color: $coloractinium;
- color: $term0;
-}
-
-.cheatsheet-periodictable-legend-color-wrapper {
- @include full-rounding;
- padding: 0.273rem;
- border: 0.136rem solid $onLayer0;
-}
-
-@mixin cheatsheet-periodictable-legend-color {
- @include full-rounding;
- min-width: 1.023rem;
- min-height: 1.023rem;
-}
-
-.cheatsheet-periodictable-legend-color-metal {
- @include cheatsheet-periodictable-legend-color;
- background-color: $colormetal;
-}
-
-.cheatsheet-periodictable-legend-color-nonmetal {
- @include cheatsheet-periodictable-legend-color;
- background-color: $colornonmetal;
-}
-
-.cheatsheet-periodictable-legend-color-noblegas {
- @include cheatsheet-periodictable-legend-color;
- background-color: $colornoblegas;
-}
-
-.cheatsheet-periodictable-legend-color-lanthanum {
- @include cheatsheet-periodictable-legend-color;
- background-color: $colorlanthanum;
-}
-
-.cheatsheet-periodictable-legend-color-actinium {
- @include cheatsheet-periodictable-legend-color;
- background-color: $coloractinium;
-}
\ No newline at end of file
diff --git a/.config/ags/scss/_colors.scss b/.config/ags/scss/_colors.scss
deleted file mode 100644
index 3e6942efd..000000000
--- a/.config/ags/scss/_colors.scss
+++ /dev/null
@@ -1,99 +0,0 @@
-$rootTransparency: 0.22; // Transparency = 1 - opacity
-$transparency: 0.75;
-
-// Transparent versions
-@if $transparent == True {
- $background: transparentize($background, $rootTransparency);
- $surface: transparentize($surface, $transparency);
- $surfaceDim: transparentize($surfaceDim, $transparency);
- $surfaceBright: transparentize($surfaceBright, $transparency);
- $surfaceContainerLowest: transparentize($surfaceContainerLowest, $transparency);
- $surfaceContainerLow: transparentize($surfaceContainerLow, $transparency);
- $surfaceContainer: transparentize($surfaceContainer, $transparency);
- $surfaceContainerHigh: transparentize($surfaceContainerHigh, $transparency);
- $surfaceContainerHighest: transparentize($surfaceContainerHighest, $transparency);
- $surfaceVariant: transparentize($surfaceVariant, $transparency);
- $inverseSurface: transparentize($inverseSurface, $transparency);
- $surfaceTint: transparentize($surfaceTint, $transparency);
-}
-
-// Others
-$subtext: $outline;
-$actiontext: mix($onBackground, $background, 85%);
-$black: black;
-$white: white;
-
-/// Color mappings for more chaotic, dynamic colors like the average rice ///
-// General
-$layer0: $background;
-$onLayer0: $onBackground;
-$layer0Hover: mix($layer0, $onLayer0, 85%);
-$layer0Active: $surfaceContainerHigh;
-$onLayer0Active: $onSurface;
-$onLayer0Inactive: mix($onLayer0, $layer0, 70%);
-$layer1: $surfaceContainerLow;
-$onLayer1: $onSurface;
-$onLayer1Inactive: mix($onLayer1, $layer1, 45%);
-$onLayer1: $onSurfaceVariant;
-$layer2: mix($surfaceContainer, $surfaceContainerHigh, 55%);
-$onLayer2: $onSurface;
-$layer3: mix($surfaceContainerHigh, $onSurface, 96%);
-$onLayer3: $onSurface;
-$layer1Hover: mix($layer1, $onLayer1, 85%);
-$layer1Active: mix($layer1, $onLayer1, 70%);
-$layer2Hover: mix($layer2, $onLayer2, 90%);
-$layer2Active: mix($layer2, $onLayer2, 80%);
-$layer3Hover: mix($layer3, $onLayer3, 90%);
-$layer3Active: mix($layer3, $onLayer3, 80%);
-// Elements
-$windowtitleOnLayer0Inactive: $onLayer0Inactive;
-$windowtitleOnLayer0: $onLayer0;
-$barspacerightOnLayer0: $onLayer0;
-$timeOnLayer1: $onLayer1;
-$dateOnLayer1: $onLayer1;
-$ramOnLayer1: $onLayer1;
-$ramLayer2: $secondaryContainer;
-$ramOnLayer2: $onSecondaryContainer;
-$swapOnLayer1: $onLayer1;
-$swapLayer2: $secondaryContainer;
-$swapOnLayer2: $onSecondaryContainer;
-$cpuOnLayer1: $onLayer1;
-$cpuLayer2: $secondaryContainer;
-$cpuOnLayer2: $onSecondaryContainer;
-$musicOnLayer1: $onLayer1;
-$musicLayer2: $secondaryContainer;
-$musicOnLayer2: $onSecondaryContainer;
-$utilsLayer2: $layer2;
-$utilsOnLayer2: $onLayer2;
-$battOnLayer1: $onLayer1;
-$battLayer2: $secondaryContainer;
-$battOnLayer2: $onSecondaryContainer;
-$workspaceOnLayer1Inactive: $onLayer1Inactive;
-$workspaceLayer3: $primary;
-$workspaceOnLayer3: $onPrimary;
-$workspaceOnLayer2: $onSecondaryContainer;
-$trayOnLayer0: $onLayer0;
-$cheatsheetTitle: $onSecondaryContainer;
-$cheatsheetColors: (
- $onSecondaryContainer,
- $onSecondaryContainer,
- $onSecondaryContainer,
- $onSecondaryContainer,
- $onSecondaryContainer,
- $onSecondaryContainer,
- $onSecondaryContainer,
- $onSecondaryContainer
-);
-
-$sessionColors: (
- $onLayer1,
- $onLayer1,
- $onLayer1,
- $onLayer1,
- $onLayer1,
- $onLayer1,
- $onLayer1
-);
-$brightnessOnLayer0: $onLayer0;
-$volumeOnLayer0: $onLayer0;
-
diff --git a/.config/ags/scss/_common.scss b/.config/ags/scss/_common.scss
deleted file mode 100644
index e12a2031f..000000000
--- a/.config/ags/scss/_common.scss
+++ /dev/null
@@ -1,380 +0,0 @@
-* {
- selection {
- background-color: $secondary;
- color: $onSecondary;
- }
-
- caret-color: $onLayer2;
-}
-
-@keyframes appear {
- from {
- opacity: 0;
- }
-
- to {
- opacity: 1;
- }
-}
-
-menu {
- @include small-rounding;
- border: 1px solid mix($surfaceContainer, $onBackground, 80%); // I hate this
- padding: 0.681rem;
- background: opacify($surfaceContainer, 1);
- color: $onSurface;
- -gtk-outline-radius: 1.159rem;
-
- animation-name: appear;
- animation-duration: 40ms;
- animation-timing-function: ease-out;
- animation-iteration-count: 1;
-}
-
-menubar>menuitem {
- border-radius: 0.545rem;
- -gtk-outline-radius: 0.545rem;
- min-width: 13.636rem;
- min-height: 2.727rem;
-}
-
-menu>menuitem {
- padding: 0.4em 1.5rem;
- background: transparent;
- transition: 0.2s ease background-color;
- border-radius: 0.545rem;
- -gtk-outline-radius: 0.545rem;
-}
-
-menu>menuitem:hover,
-menu>menuitem:focus {
- background-color: $layer2Hover;
-}
-
-menu>menuitem:active {
- background-color: $layer2Active;
-}
-
-radio {
- @include full-rounding;
- margin: 0.273rem;
- min-width: 15px;
- min-height: 15px;
- border: 0.068rem solid $outline;
-}
-
-// radio:first-child {
-// background-color: red;
-// }
-
-radio:checked {
- min-width: 8px;
- min-height: 8px;
- background-color: $onPrimary;
- border: 0.477rem solid $primary;
-}
-
-tooltip {
- animation-name: appear;
- animation-duration: 100ms;
- animation-timing-function: ease-out;
- animation-iteration-count: 1;
- @include normal-rounding;
- background-color: opacify($color: $inverseSurface, $amount: 1);
- color: $inverseOnSurface;
-}
-
-/////////////////////////////////////////
-// Emoji Chooser structure
-// popover
-// ├── box.emoji-searchbar
-// │ ╰── entry.search
-// ╰── box.emoji-toolbar
-// ├── button.image-button.emoji-section
-// ├── ...
-// ╰── button.image-button.emoji-section
-
-popover {
- @include elevation-border-softer;
- padding: 0.681rem;
- background: $surfaceContainerHigh;
- color: $onSurface;
- border-radius: 1.159rem;
- -gtk-outline-radius: 1.159rem;
-
- animation-name: appear;
- animation-duration: 40ms;
- animation-timing-function: ease-out;
- animation-iteration-count: 1;
-}
-
-
-/////////////////////////////////////////
-
-.configtoggle-box {
- padding: 0.205rem 0.341rem;
-}
-
-.configtoggle-reset {
- @include small-rounding;
- color: $onLayer2;
- background-color: $layer2;
- min-width: 2.045rem;
- min-height: 2.045rem;
-}
-
-.configtoggle-reset:focus,
-.configtoggle-reset:hover {
- background-color: $layer2Hover;
-}
-
-.configtoggle-reset:active {
- background-color: $layer2Active;
-}
-
-
-.switch-bg {
- @include element_decel;
- @include full-rounding;
- border: 0.136rem solid $onSurface;
- min-width: 2.864rem;
- min-height: 1.637rem;
-}
-
-.switch-bg-true {
- background-color: $primary;
- border: 0.136rem solid $primary;
-}
-
-.switch-fg {
- @include full-rounding;
- @include menu_decel;
- background-color: $onSurface;
- color: $layer1;
- min-width: 0.819rem;
- min-height: 0.819rem;
- margin-left: 0.477rem;
-}
-
-.switch-fg-true {
- background-color: $onPrimary;
- color: $primary;
- min-width: 1.431rem;
- min-height: 1.431rem;
- margin-left: 1.431rem;
-}
-
-.switch-fg-toggling-false {
- @include menu_decel;
- min-width: 1.636rem;
- min-height: 0.819rem;
-}
-
-.segment-container {
- @include full-rounding;
- border: 0.068rem solid $outline;
-}
-
-.segment-container>*:first-child {
- border-top-left-radius: 9999px;
- border-bottom-left-radius: 9999px;
-}
-
-.segment-container>* {
- border-right: 0.068rem solid $outline;
- padding: 0.341rem 0.682rem;
-}
-
-.segment-container>*:last-child {
- border-right: 0rem solid transparent;
- border-top-right-radius: 9999px;
- border-bottom-right-radius: 9999px;
-}
-
-.segment-btn {
- color: $onSurface;
-}
-
-.segment-btn:focus,
-.segment-btn:hover {
- background-color: $layer0Hover;
-}
-
-.segment-btn-enabled {
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
-}
-
-.segment-btn-enabled:hover,
-.segment-btn-enabled:focus {
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
-}
-
-.multipleselection-container {}
-
-.multipleselection-btn {
- @include small-rounding;
- padding: 0rem 0.341rem;
- border: 0.034rem solid $outline;
- color: $onSurface;
-}
-
-.multipleselection-btn:focus,
-.multipleselection-btn:hover {
- background-color: $layer0Hover;
- color: $onSurface;
-}
-
-.multipleselection-btn-enabled {
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
-}
-
-.multipleselection-btn-enabled:hover,
-.multipleselection-btn-enabled:focus {
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
-}
-
-.gap-v-5 {
- min-height: 0.341rem;
-}
-
-.gap-h-5 {
- min-width: 0.341rem;
-}
-
-.gap-v-10 {
- min-height: 0.682rem;
-}
-
-.gap-h-10 {
- min-width: 0.682rem;
-}
-
-.gap-v-15 {
- min-height: 1.023rem;
-}
-
-.gap-h-15 {
- min-width: 1.023rem;
-}
-
-.tab-btn {
- @include small-rounding;
- @include element_decel;
- min-height: 2.5rem;
- color: $onLayer0;
-}
-
-.tab-btn:hover {
- background-color: $layer0Hover;
-}
-
-.tab-btn:focus {
- background-color: $surfaceContainerLow;
-}
-
-.tab-btn-active>box>label {
- color: $primary;
-}
-
-.tab-indicator {
- transition: 180ms ease-in-out; // Doesn't look that good, but it syncs with the GtkStack
- min-height: 0.205rem;
- padding: 0rem 1.023rem;
- color: $primary;
-}
-
-.tab-icon {
- @include element_decel;
- @include full-rounding;
- min-width: 2.25rem;
- min-height: 2.25rem;
- font-size: 1.406rem;
- color: $onSurface;
-}
-
-.tab-icon-active {
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
-}
-
-.tab-icon-expandable {
- transition: 0ms;
- @include full-rounding;
- min-width: 2.25rem;
- min-height: 2.25rem;
- font-size: 1.406rem;
- color: $onSurface;
- padding: 0rem;
-}
-
-.tab-icon-expandable-active {
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
- padding: 0rem 0.545rem;
- min-width: 9.545rem;
-}
-
-widget {
- @include small-rounding;
-}
-
-.spinbutton {
- @include small-rounding;
- color: $onLayer2;
- background-color: $layer2;
- min-width: 2.045rem;
- min-height: 2.045rem;
- caret-color: $onLayer2;
-
- entry {
- color: $onLayer2;
- margin: 0.477rem 0.614rem;
- }
-
- button {
- @include unsharpen-rounding;
- min-width: 2.045rem;
- min-height: 2.045rem;
- -gtk-outline-radius: $rounding_small;
- }
-
- button.up {
- // Only apply rounding to (+) button
- border-top-right-radius: $rounding_small;
- border-bottom-right-radius: $rounding_small;
- }
-
- // button:focus, // Looks weird after clicking cuz it'll highlight both + and -
- button:hover {
- background-color: $layer2Hover;
- }
-
- button:active {
- background-color: $layer2Active;
- }
-}
-
-.spinbutton-reset {
- @include small-rounding;
- color: $onLayer2;
- background-color: $layer2;
- min-width: 2.045rem;
- min-height: 2.045rem;
-}
-
-.spinbutton-reset:focus,
-.spinbutton-reset:hover {
- background-color: $layer2Hover;
-}
-
-.spinbutton-reset:active {
- background-color: $layer2Active;
-}
-
-textview {
- caret-color: $onBackground;
-}
\ No newline at end of file
diff --git a/.config/ags/scss/_desktopbackground.scss b/.config/ags/scss/_desktopbackground.scss
deleted file mode 100644
index 2dda9a12d..000000000
--- a/.config/ags/scss/_desktopbackground.scss
+++ /dev/null
@@ -1,92 +0,0 @@
-.bg-wallpaper-transition {
- transition: 1000ms cubic-bezier(0.05, 0.7, 0.1, 1);
- font-size: 1px;
-}
-
-@mixin bg-textshadow {
- // text-shadow: mix($shadow, $secondaryContainer, 50%) 1px 0px 3px;
-}
-
-.bg-time-box {
- @include large-rounding;
- margin: 2.045rem;
- padding: 0.682rem;
-}
-
-.bg-time-clock {
- @include titlefont;
- @include bg-textshadow;
- font-size: 5.795rem;
- color: $onLayer0;
-}
-
-.bg-time-date {
- @include titlefont;
- @include bg-textshadow;
- font-size: 2.591rem;
- color: $onLayer0;
-}
-
-.bg-distro-box {
- @include large-rounding;
- margin: 2.045rem;
- padding: 0.682rem;
-}
-
-.bg-distro-txt {
- @include titlefont;
- @include bg-textshadow;
- font-size: 1.432rem;
- color: $onLayer0;
-}
-
-.bg-distro-name {
- @include titlefont;
- @include bg-textshadow;
- font-size: 1.432rem;
- color: $onSecondaryContainer;
-}
-
-.bg-graph {
- color: rgba(255, 255, 255, 0.5);
- border-radius: 0.614rem;
- border: 0.682rem solid;
-}
-
-.bg-quicklaunch-title {
- @include mainfont;
- color: $onSurfaceVariant;
-}
-
-.bg-quicklaunch-btn {
- @include mainfont;
- @include full-rounding;
- background-color: $layer2;
- color: $onLayer2;
- min-width: 4.432rem;
- min-height: 2.045rem;
- padding: 0.273rem 0.682rem;
-}
-
-.bg-quicklaunch-btn:hover,
-.bg-quicklaunch-btn:focus {
- background-color: $layer2Hover;
-}
-
-.bg-quicklaunch-btn:active {
- background-color: $layer2Active;
-}
-
-.bg-system-bg {
- @include normal-rounding;
- // background-color: $background;
-}
-
-.bg-system-circprog {
- @include fluent_decel_long;
- min-width: 0.205rem; // Trough stroke width
- min-height: 4.091rem; // Diameter
- font-size: 0px;
- padding: 0rem;
- background-color: $layer2;
-}
\ No newline at end of file
diff --git a/.config/ags/scss/_dock.scss b/.config/ags/scss/_dock.scss
deleted file mode 100644
index 2e087ffe8..000000000
--- a/.config/ags/scss/_dock.scss
+++ /dev/null
@@ -1,42 +0,0 @@
-.dock-bg {
- @include large-rounding;
- @include elevation2;
- background-color: $layer0;
- padding: 0.682rem;
-}
-
-.dock-app-btn-animate {
- transition-property: background-color;
- transition-duration: 0.5s;
-}
-
-.dock-app-btn {
- @include normal-rounding;
- padding: 0.273rem;
-}
-
-.pinned-dock-app-btn {
- @include normal-rounding;
- padding: 0.273rem;
- background-color: $layer0Hover;
-}
-
-.dock-app-btn:hover,
-.dock-app-btn:focus {
- background-color: $layer0Hover;
-}
-
-.dock-app-btn:active {
- background-color: $layer0Active;
-}
-
-.dock-app-icon {
- min-width: 3.409rem;
- min-height: 3.409rem;
- font-size: 3.409rem;
-}
-
-.dock-separator {
- min-width: 0.068rem;
- background-color: $outline;
-}
diff --git a/.config/ags/scss/_lib_classes.scss b/.config/ags/scss/_lib_classes.scss
deleted file mode 100644
index d375ec87d..000000000
--- a/.config/ags/scss/_lib_classes.scss
+++ /dev/null
@@ -1,515 +0,0 @@
-.test {
- background-image: linear-gradient(45deg, #f4d609 0%, #f4d609 10%, #212121 10%, #212121 20%, #f4d609 20%, #f4d609 30%, #212121 30%,
- #212121 40%, #f4d609 40%, #f4d609 50%, #212121 50%, #212121 60%, #f4d609 60%,
- #f4d609 70%, #212121 70%, #212121 80%, #f4d609 80%, #f4d609 90%, #212121 90%, #212121 100%);
- background-repeat: repeat;
-}
-
-.test-size {
- min-height: 3rem;
- min-width: 3rem;
-}
-
-.txt-title {
- @include titlefont;
- font-size: 2.045rem;
-}
-
-.txt-title-small {
- @include titlefont;
- font-size: 1.364rem;
-}
-
-.techfont {
- @include techfont;
-}
-
-.txt-reading {
- @include readingfont;
-}
-
-.no-anim {
- @include noanim;
-}
-
-.txt {
- color: $onBackground;
- caret-color: $onBackground;
-}
-
-.txt-primary {
- color: $primary;
-}
-
-.txt-onSecondaryContainer {
- color: $onSecondaryContainer;
-}
-
-.txt-onSurfaceVariant {
- color: $onSurfaceVariant;
-}
-
-.txt-onLayer1 {
- color: $onLayer1;
-}
-
-.txt-shadow {
- text-shadow: 1px 2px 8px rgba(0, 0, 0, 0.69);
- margin: 10px;
-}
-
-.txt-gigantic {
- @include mainfont;
- font-size: 3rem;
-}
-
-.txt-massive {
- @include mainfont;
- font-size: 2.7273rem;
-}
-
-.txt-hugerass {
- @include mainfont;
- font-size: 2.045rem;
-}
-
-.txt-hugeass {
- @include mainfont;
- font-size: 1.8182rem;
-}
-
-.txt-larger {
- @include mainfont;
- font-size: 1.6363rem;
-}
-
-.txt-large {
- //16pt
- @include mainfont;
- font-size: 1.4545rem;
-}
-
-.txt-norm {
- //14pt
- @include mainfont;
- font-size: 1.2727rem;
-}
-
-.txt-small {
- //12pt
- @include mainfont;
- font-size: 1.0909rem;
-}
-
-.txt-smallie {
- //11pt
- @include mainfont;
- font-size: 1rem;
-}
-
-.txt-smaller {
- //10pt
- @include mainfont;
- font-size: 0.9091rem;
-}
-
-.txt-tiny {
- @include mainfont;
- font-size: 0.7273rem;
-}
-
-.txt-poof {
- font-size: 0px;
-}
-
-.txt-subtext {
- @include subtext;
-}
-
-.txt-action {
- @include actiontext;
-}
-
-.txt-thin {
- font-weight: 300;
-}
-
-.txt-semibold {
- font-weight: 500;
-}
-
-.txt-bold {
- font-weight: bold;
-}
-
-.txt-italic {
- font-style: italic;
-}
-
-.btn-primary {
- @include full-rounding;
- background-color: $primary;
- color: $onPrimary;
- padding: 0.682rem 1.023rem;
-}
-
-.titlefont {
- @include titlefont;
-}
-
-.mainfont {
- @include mainfont;
-}
-
-.icon-material {
- @include icon-material;
-}
-
-.icon-nerd {
- @include icon-nerd;
-}
-
-.separator-line {
- background-color: mix($subtext, $surface, 50%);
- min-width: 0.068rem;
- min-height: 0.068rem;
-}
-
-.separator-circle {
- @include full-rounding;
- background-color: $outline;
- margin: 0rem 0.682rem;
- min-width: 0.273rem;
- min-height: 0.273rem;
-}
-
-.spacing-h-3>* {
- margin-right: 0.205rem;
-}
-
-.spacing-h-3>*:last-child {
- margin-right: 0rem;
-}
-
-.spacing-v-3>* {
- margin-bottom: 0.205rem;
-}
-
-.spacing-v-3>*:last-child {
- margin-bottom: 0rem;
-}
-
-.spacing-v-15>* {
- margin-bottom: 1.023rem;
-}
-
-.spacing-v-15>*:last-child {
- margin-bottom: 0rem;
-}
-
-.spacing-h-15>* {
- margin-right: 1.023rem;
-}
-
-.spacing-h-15>*:last-child {
- margin-right: 0rem;
-}
-
-.spacing-h-15>revealer>* {
- margin-right: 1.023rem;
-}
-
-.spacing-h-15>revealer:last-child>* {
- margin-right: 0rem;
-}
-
-.spacing-h-15>scrolledwindow>* {
- margin-right: 1.023rem;
-}
-
-.spacing-h-15>scrolledwindow:last-child>* {
- margin-right: 0rem;
-}
-
-.spacing-v-5>box {
- margin-bottom: 0.341rem;
-}
-
-.spacing-v-5>box:last-child {
- margin-bottom: 0rem;
-}
-
-.spacing-v-5>* {
- margin-bottom: 0.341rem;
-}
-
-.spacing-v-5>*:last-child {
- margin-bottom: 0rem;
-}
-
-.spacing-v-5-revealer>revealer>* {
- margin-bottom: 0.341rem;
-}
-
-.spacing-v-5-revealer>revealer:last-child>* {
- margin-bottom: 0rem;
-}
-
-.spacing-v-5-revealer>scrolledwindow>* {
- margin-bottom: 0.341rem;
-}
-
-.spacing-v-5-revealer>scrolledwindow:last-child>* {
- margin-bottom: 0rem;
-}
-
-.spacing-h-4>* {
- margin-right: 0.273rem;
-}
-
-.spacing-h-4>*:last-child {
- margin-right: 0rem;
-}
-
-.spacing-h-4>overlay>*:first-child {
- margin-right: 0.273rem;
-}
-
-.spacing-h-4>overlay:last-child>* {
- margin-right: 0rem;
-}
-
-.spacing-h-5>* {
- margin-right: 0.341rem;
-}
-
-.spacing-h-5>*:last-child {
- margin-right: 0rem;
-}
-
-.spacing-h-5>widget>* {
- margin-right: 0.341rem;
-}
-
-.spacing-h-5>widget:last-child>* {
- margin-right: 0rem;
-}
-
-.spacing-h-5>revealer>* {
- margin-right: 0.341rem;
-}
-
-.spacing-h-5>revealer:last-child>* {
- margin-right: 0rem;
-}
-
-.spacing-h-5>scrolledwindow>* {
- margin-right: 0.341rem;
-}
-
-.spacing-h-5>scrolledwindow:last-child>* {
- margin-right: 0rem;
-}
-
-.spacing-v-minus5>* {
- margin-bottom: -0.341rem;
-}
-
-.spacing-v-minus5>*:last-child {
- margin-bottom: 0rem;
-}
-
-.spacing-h-10>* {
- margin-right: 0.682rem;
-}
-
-.spacing-h-10>*:last-child {
- margin-right: 0rem;
-}
-
-.spacing-h-10>revealer>* {
- margin-right: 0.682rem;
-}
-
-.spacing-h-10>revealer:last-child>* {
- margin-right: 0rem;
-}
-
-.spacing-h-10>scrolledwindow>* {
- margin-right: 0.682rem;
-}
-
-.spacing-h-10>scrolledwindow:last-child>* {
- margin-right: 0rem;
-}
-
-.spacing-h-10>flowboxchild>* {
- margin-right: 0.682rem;
-}
-
-.spacing-h-10>flowboxchild:last-child>* {
- margin-right: 0rem;
-}
-
-.spacing-v-10>* {
- margin-bottom: 0.682rem;
-}
-
-.spacing-v-10>*:last-child {
- margin-bottom: 0rem;
-}
-
-.spacing-h-20>* {
- margin-right: 1.364rem;
-}
-
-.spacing-h-20>*:last-child {
- margin-right: 0rem;
-}
-
-.spacing-v-20>* {
- margin-bottom: 1.364rem;
-}
-
-.spacing-v-20>*:last-child {
- margin-bottom: 0rem;
-}
-
-.spacing-h-30>* {
- margin-right: 1.364rem;
-}
-
-.spacing-h-30>*:last-child {
- margin-right: 0rem;
-}
-
-.spacing-v-30>* {
- margin-bottom: 1.364rem;
-}
-
-.spacing-v-30>*:last-child {
- margin-bottom: 0rem;
-}
-
-.anim-enter {
- @include anim-enter;
-}
-
-.anim-exit {
- @include anim-exit;
-}
-
-.button-minsize {
- @include button-minsize;
-}
-
-@each $spacing in (2, 5, 8, 10, 15, 20) {
- @each $dir in ("top", "bottom", "left", "right") {
- .margin-#{$dir}-#{$spacing} {
- margin-#{$dir}: 0.068rem * $spacing;
- }
- .padding-#{$dir}-#{$spacing} {
- padding-#{$dir}: 0.068rem * $spacing;
- }
- }
- .padding-#{$spacing} {
- padding: 0.068rem * $spacing;
- }
- .margin-#{$spacing} {
- padding: 0.068rem * $spacing;
- }
-}
-
-.width-10 {
- min-width: 0.682rem;
-}
-
-.height-10 {
- min-width: 0.682rem;
-}
-
-.invisible {
- opacity: 0;
- background-color: transparent;
- color: transparent;
-}
-
-.spacing-h--5>box {
- margin-right: -0.341rem;
-}
-
-.spacing-h--5>box:last-child {
- margin-right: 0rem;
-}
-
-.spacing-v--5>* {
- margin-bottom: -0.341rem;
-}
-
-.spacing-v--5>*:last-child {
- margin-bottom: 0rem;
-}
-
-.spacing-h--10>* {
- margin-left: -1.364rem;
-}
-
-.spacing-h--10>*:first-child {
- margin-left: 0rem;
-}
-
-.spacing-v--10>* {
- margin-bottom: -0.682rem;
-}
-
-.spacing-v--10>*:last-child {
- margin-bottom: 0rem;
-}
-
-.spacing-v--10>* {
- margin-bottom: -0.682rem;
-}
-
-.spacing-v--10>*:last-child {
- margin-bottom: 0rem;
-}
-
-.spacing-h--20>* {
- margin-left: -1.364rem;
-}
-
-.spacing-h--20>*:first-child {
- margin-left: 0rem;
-}
-
-.instant {
- transition: 0ms;
-}
-
-.menu-decel {
- @include menu_decel;
-}
-
-.element-show {
- @include element_easeInOut;
-}
-
-.element-hide {
- @include element_easeInOut;
-}
-
-.element-move {
- @include element_easeInOut;
-}
-
-.element-decel {
- @include element_decel;
-}
-
-.element-bounceout {
- @include element_bounceOut;
-}
-
-.element-accel {
- @include element_accel;
-}
\ No newline at end of file
diff --git a/.config/ags/scss/_lib_mixins.scss b/.config/ags/scss/_lib_mixins.scss
deleted file mode 100644
index 3bae4553c..000000000
--- a/.config/ags/scss/_lib_mixins.scss
+++ /dev/null
@@ -1,187 +0,0 @@
-// Common colors
-$hovercolor: $surfaceContainerHigh;
-$activecolor: $surfaceContainerHighest;
-$rounding_unsharpen: 0.136rem;
-$rounding_verysmall: 0.545rem;
-$rounding_small: 0.818rem;
-$rounding_mediumsmall: 0.955rem;
-$rounding_medium: 1.159rem;
-$rounding_mediumlarge: 1.364rem;
-$rounding_large: 1.705rem;
-
-// Common rules
-@mixin unsharpen-rounding {
- border-radius: $rounding_unsharpen;
-}
-
-@mixin verysmall-rounding {
- border-radius: $rounding_verysmall;
- -gtk-outline-radius: $rounding_verysmall;
-}
-
-@mixin small-rounding {
- border-radius: $rounding_small;
- -gtk-outline-radius: $rounding_small;
-}
-
-@mixin normal-rounding {
- border-radius: $rounding_medium;
- -gtk-outline-radius: $rounding_medium;
-}
-
-@mixin large-rounding {
- border-radius: $rounding_large;
- -gtk-outline-radius: $rounding_large;
-}
-
-@mixin full-rounding {
- border-radius: 9999px;
- -gtk-outline-radius: 9999px;
-}
-
-// @mixin symbolic-icon {
-// -gtk-icon-theme: 'Adwaita';
-// }
-
-@mixin titlefont {
- // Geometric sans-serif
- font-family: "Gabarito", "Poppins", "Readex Pro", "Lexend", sans-serif;
-}
-
-@mixin mainfont {
- // Other clean sans-serif
- font-family: "Rubik", "Adwaita Sans", "42dotSans", "Geist", "AR One Sans", "Reddit Sans", "Inter",
- "Roboto", "Ubuntu", "Noto Sans", sans-serif;
- // font-weight: 500;
-}
-
-@mixin icon-material {
- // Material Design Icons
- font-family: "Material Symbols Rounded", "MaterialSymbolsRounded", "Material Symbols Outlined",
- "Material Symbols Sharp";
-}
-
-@mixin icon-nerd {
- // Nerd Fonts
- font-family: "SpaceMono NF", "SpaceMono Nerd Font", "JetBrains Mono NF",
- "JetBrains Mono Nerd Font", monospace;
-}
-
-@mixin techfont {
- // Monospace for sys info n stuff. Doesn't have to be a nerd font, but it's cool.
- font-family: "JetBrains Mono NF", "JetBrains Mono Nerd Font",
- "JetBrains Mono NL", "SpaceMono NF", "SpaceMono Nerd Font", monospace;
-}
-
-@mixin readingfont {
- // The most readable fonts, for a comfortable reading experience
- // in stuff like AI chat on sidebar
- font-family: "Readex Pro", "Lexend", "Noto Sans", sans-serif;
- // font-weight: 500;
-}
-
-@mixin subtext {
- color: $subtext;
-}
-
-@mixin actiontext {
- color: $actiontext;
-}
-
-$elevation_margin: 0.476rem;
-
-@mixin elevation2 {
- box-shadow: 0px 2px 3px transparentize($shadow, 0.55);
- margin: $elevation_margin;
-}
-
-@mixin elevation2-margin {
- margin: $elevation_margin;
-}
-
-@mixin elevation2-padding {
- padding: $elevation_margin;
-}
-
-@mixin elevation3 {
- box-shadow: 0px 2px 5px $shadow;
- margin: $elevation_margin;
-}
-
-@mixin menu_decel {
- transition: 300ms cubic-bezier(0.1, 1, 0, 1);
-}
-
-@mixin menu_decel_fast {
- transition: 170ms cubic-bezier(0.1, 1, 0, 1);
-}
-
-@mixin menu_accel {
- transition: 160ms cubic-bezier(0.38, 0.04, 1, 0.07);
-}
-
-@mixin menu_accel_fast {
- transition: 100ms cubic-bezier(0.38, 0.04, 1, 0.07);
-}
-
-@mixin fluent_decel {
- transition: 200ms cubic-bezier(0.1, 1, 0, 1);
-}
-
-@mixin fluent_decel_long {
- transition: 1000ms cubic-bezier(0.1, 1, 0, 1);
-}
-
-@mixin fluent_accel {
- transition: 150ms cubic-bezier(0.42, 0, 1, 1);
-}
-
-@mixin noanim {
- transition: 0ms;
-}
-
-@mixin anim-enter {
- transition: 200ms cubic-bezier(0.05, 0.7, 0.1, 1);
-}
-
-@mixin anim-exit {
- transition: 150ms cubic-bezier(0.3, 0, 0.8, 0.15);
-}
-
-@mixin element_decel {
- transition: 300ms cubic-bezier(0, 0.55, 0.45, 1);
-}
-
-@mixin element_bounceOut {
- transition: transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
-}
-
-@mixin element_accel {
- transition: 300ms cubic-bezier(0.55, 0, 1, 0.45);
-}
-
-@mixin element_easeInOut {
- transition: 300ms cubic-bezier(0.85, 0, 0.15, 1);
-}
-
-@mixin elevation-border-softer {
- border-top: 1px solid mix($surface, $onSurface, 86%);
- border-left: 1px solid mix($surface, $onSurface, 86%);
- border-right: 1px solid mix($surface, $onSurface, 90%);
- border-bottom: 1px solid mix($surface, $onSurface, 90%);
-}
-
-@mixin elevation-border {
- border-top: 1px solid $surfaceContainer;
- border-left: 1px solid $surfaceContainer;
- border-right: 1px solid $surfaceContainer;
- border-bottom: 1px solid $surfaceContainer;
-}
-
-@mixin button-minsize {
- min-width: 2.727rem;
- min-height: 2.727rem;
-}
-
-$white: white;
-$black: black;
diff --git a/.config/ags/scss/_music.scss b/.config/ags/scss/_music.scss
deleted file mode 100644
index 7450c5041..000000000
--- a/.config/ags/scss/_music.scss
+++ /dev/null
@@ -1,159 +0,0 @@
-@import 'material';
-@import 'musicmaterial';
-@import './wal';
-@import 'musicwal';
-@import './colors';
-@import './lib_mixins';
-$music_transparentize_amount: 0.3;
-$music_gradient1: mix($color1, $background, 50%);
-
-// @if $darkmode == True {
-// $music_gradient1: mix($color1, $background, 30%);
-// }
-
-$music_gradient2: $color3;
-$music_gradient3: $color5;
-$music_colorstart_transparentize: 0.3;
-$music_extra_transparentize: 0.15;
-
-$secondaryContainer: transparentize(mix(mix($background, $color2, 50%), $color6, 80%), 0.5);
-$onSecondaryContainer: mix($color7, $color2, 90%);
-@if $darkmode == False {
- $onSecondaryContainer: mix($onSecondaryContainer, black, 50%);
-} @else {
- $onSecondaryContainer: mix($onSecondaryContainer, white, 50%);
-}
-
-
-.osd-music {
- @include menu_decel;
- @include elevation2;
- margin-top: 0.313rem;
- @include normal-rounding;
- // min-height: 7.159rem;
- min-width: 29.659rem;
- background-color: $layer0;
- padding: 0rem 1.023rem;
- background: // Inspired by Amberol
- linear-gradient(127deg, transparentize($music_gradient1, $music_colorstart_transparentize), transparentize($music_gradient1, $music_colorstart_transparentize - $music_transparentize_amount + $music_extra_transparentize) 70.71%),
- linear-gradient(217deg, transparentize($music_gradient2, $music_colorstart_transparentize), transparentize($music_gradient2, $music_colorstart_transparentize - $music_transparentize_amount + $music_extra_transparentize) 70.71%),
- radial-gradient(circle at 0% 100%, $color4 13%, rgba(0, 0, 0, 0) 100%),
- linear-gradient(336deg, transparentize($music_gradient3, $music_colorstart_transparentize), transparentize($music_gradient3, $music_colorstart_transparentize - $music_transparentize_amount + $music_extra_transparentize) 70.71%),
- linear-gradient($background, $background), // We don't want wallpaper tint, so here's a fully opaque surface
- ;
-}
-
-
-.osd-music-cover-fallback {
- @include element_decel;
- @include small-rounding;
- // margin: 1.023rem;
- min-width: 7.5rem;
- min-height: 7.5rem;
- background-color: $layer1;
- color: $onSecondaryContainer;
-}
-
-.osd-music-cover {
- @include small-rounding;
- @include menu_decel;
- // Must be -top and -bottom or it'll mess up horizontal spacing
- margin-top: 1.023rem;
- margin-bottom: 1.023rem;
- min-width: 7.5rem;
- min-height: 7.5rem;
-}
-
-.osd-music-cover-art {
- @include small-rounding;
- min-width: 7.5rem;
- min-height: 7.5rem;
- background-size: cover;
- background-position: center;
-}
-
-.osd-music-info {
- margin: 1.023rem 0rem;
-}
-
-.osd-music-title {
- @include element_decel;
- @include titlefont;
- font-size: 1.364rem;
- color: $onSecondaryContainer;
-}
-
-.osd-music-artists {
- @include element_decel;
- @include mainfont;
- font-size: 0.955rem;
- color: mix($onSecondaryContainer, $secondaryContainer, 80%);
-}
-
-.osd-music-pill {
- @include element_decel;
- @include full-rounding;
- @include titlefont;
- min-width: 1.833rem;
- padding: 0.273rem 0.682rem;
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
-}
-
-.osd-music-controls {
- @include element_decel;
- @include full-rounding;
- @include titlefont;
- min-width: 1.833rem;
- padding: 0.205rem;
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
-}
-
-.osd-music-controlbtn {
- @include menu_decel;
- min-width: 2.045rem;
- min-height: 2.045rem;
- @include full-rounding;
-}
-
-.osd-music-controlbtn:hover,
-.osd-music-controlbtn:focus {
- background-color: mix($secondaryContainer, $onSecondaryContainer, 90%);
-}
-
-.osd-music-controlbtn:active {
- background-color: mix($secondaryContainer, $onSecondaryContainer, 85%);
-}
-
-.osd-music-controlbtn-txt {
- @include element_decel;
- transition: 100ms cubic-bezier(0.05, 0.7, 0.1, 1);
- @include icon-material;
- font-size: 1.364rem;
- margin: -0.1rem 0rem;
-}
-
-.osd-music-circprog {
- @include fluent_decel_long;
- min-width: 0.409rem; // width of progress
- min-height: 3.068rem;
- padding: 0.273rem;
- color: $onSecondaryContainer;
-}
-
-.osd-music-playstate {
- @include menu_decel;
- min-height: 3.068rem;
- min-width: 3.068rem;
- border-radius: 10rem;
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
-}
-
-.osd-music-playstate-btn>label {
- transition: 50ms cubic-bezier(0.05, 0.7, 0.1, 1);
- @include icon-material;
- font-size: 1.364rem;
- margin: -0.1rem 0rem;
-}
\ No newline at end of file
diff --git a/.config/ags/scss/_notifications.scss b/.config/ags/scss/_notifications.scss
deleted file mode 100644
index 152ead0d9..000000000
--- a/.config/ags/scss/_notifications.scss
+++ /dev/null
@@ -1,255 +0,0 @@
-@mixin notif-rounding {
- @include normal-rounding;
-}
-
-.notif-low {
- @include notif-rounding;
- background-color: $layer2;
- color: $onLayer2;
- padding: $rounding_small;
- padding-right: $rounding_small + 0.545rem;
-}
-
-.notif-normal {
- @include notif-rounding;
- background-color: $layer2;
- color: $onLayer2;
- padding: $rounding_small;
- padding-right: $rounding_small + 0.545rem;
-}
-
-.notif-critical {
- @include notif-rounding;
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
- padding: $rounding_small;
- padding-right: $rounding_small + 0.545rem;
-}
-
-.notif-clicked-low {
- background-color: $layer1Hover;
-}
-
-.notif-clicked-normal {
- background-color: $layer1Hover;
-}
-
-.notif-clicked-critical {
- background-color: $onSecondary;
- color: $onSecondaryContainer;
-}
-
-.popup-notif-low {
- @include notif-rounding;
- min-width: 30.682rem;
- background-color: $layer2;
-
- @if $transparent ==True {
- background-color: $layer0;
- }
-
- border: 0.034rem solid $outlineVariant;
- color: $onLayer2;
- padding: $rounding_small;
- padding-right: $rounding_small + 0.545rem;
-}
-
-.popup-notif-normal {
- @include notif-rounding;
- min-width: 30.682rem;
- background-color: $layer2;
-
- @if $transparent ==True {
- background-color: $layer0;
- }
-
- border: 0.034rem solid $outlineVariant;
- color: $onLayer2;
- padding: $rounding_small;
- padding-right: $rounding_small + 0.545rem;
-}
-
-.popup-notif-critical {
- @include notif-rounding;
- min-width: 30.682rem;
- background-color: $secondaryContainer;
- border: 0.034rem solid $onSecondaryContainer;
- color: $onSecondaryContainer;
- padding: $rounding_small;
- padding-right: $rounding_small + 0.545rem;
-}
-
-.popup-notif-clicked-low {
- background-color: $surfaceContainerLow;
-}
-
-.popup-notif-clicked-normal {
- background-color: $surfaceContainerLow;
-}
-
-.popup-notif-clicked-critical {
- background-color: $onSecondary;
- color: $onSecondaryContainer;
-}
-
-.notif-body-low {
- color: $outline;
-}
-
-.notif-body-normal {
- color: $outline;
-}
-
-.notif-body-critical {
- color: mix($onSecondaryContainer, $secondaryContainer, 67%);
-}
-
-.notif-icon {
- @include full-rounding;
- min-width: 3.409rem;
- min-height: 3.409rem;
- font-size: 2.182rem;
-}
-
-.notif-icon-material {
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
-}
-
-.notif-icon-material-low {
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
-}
-
-.notif-icon-material-normal {
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
-}
-
-.notif-icon-material-critical {
- background-color: $secondary;
- color: $onSecondary;
-}
-
-.notif-expand-btn {
- @include notif-rounding;
- min-width: 1.841rem;
- min-height: 1.841rem;
-}
-
-.notif-expand-btn:hover,
-.notif-expand-btn:focus {
- background: $layer2Hover;
-}
-
-.notif-expand-btn:active {
- background: $layer2Active;
-}
-
-.notif-listaction-btn {
- @include notif-rounding;
- padding: 0.341rem 0.682rem;
-}
-
-.notif-listaction-btn:hover,
-.notif-listaction-btn:focus {
- background-color: $layer2Hover;
-}
-
-.notif-listaction-btn:active {
- background-color: $layer2Active;
-}
-
-.notif-listaction-btn-enabled {
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
-}
-
-.notif-listaction-btn-enabled:hover,
-.notif-listaction-btn-enabled:focus {
- background-color: mix($secondaryContainer, $onSecondaryContainer, 90%);
-}
-
-.notif-listaction-btn-enabled:active {
- background-color: mix($secondaryContainer, $onSecondaryContainer, 75%);
-}
-
-.osd-notif {
- @include notif-rounding;
- background-color: $layer0;
- min-width: 30.682rem;
-}
-
-.notif-circprog-low {
- transition: 0ms linear;
- min-width: 0.136rem; // line width
- min-height: 3.136rem;
- padding: 0rem;
- color: $onSecondaryContainer;
-}
-
-.notif-circprog-normal {
- transition: 0ms linear;
- min-width: 0.136rem; // line width
- min-height: 3.136rem;
- padding: 0rem;
- color: $onSecondaryContainer;
-}
-
-.notif-circprog-critical {
- transition: 0ms linear;
- min-width: 0.136rem; // line width
- min-height: 3.136rem;
- padding: 0rem;
- color: $secondaryContainer;
-}
-
-.notif-actions {
- min-height: 2.045rem;
-}
-
-.notif-action {
- @include small-rounding;
-}
-
-.notif-action-low {
- background-color: $surfaceContainerHighest;
- color: $onLayer2;
-}
-
-.notif-action-low:focus,
-.notif-action-low:hover {
- border: 0.040rem solid $outlineVariant;
-}
-
-.notif-action-low:active {
- background-color: $surfaceBright;
-}
-
-.notif-action-normal {
- background-color: $surfaceContainerHighest;
- color: $onSurface;
-}
-
-.notif-action-normal:focus,
-.notif-action-normal:hover {
- border: 0.040rem solid $outlineVariant;
-}
-
-.notif-action-normal:active {
- background-color: $surfaceBright;
-}
-
-.notif-action-critical {
- background-color: mix($secondary, $onSecondary, 30%);
- color: $onSurfaceVariant;
-}
-
-.notif-action-critical:focus,
-.notif-action-critical:hover {
- border: 0.040rem solid $outline;
-}
-
-.notif-action-critical:active {
- background-color: mix($secondary, $onSecondary, 40%);
-}
diff --git a/.config/ags/scss/_osd.scss b/.config/ags/scss/_osd.scss
deleted file mode 100644
index 44b808120..000000000
--- a/.config/ags/scss/_osd.scss
+++ /dev/null
@@ -1,202 +0,0 @@
-// .osd-window {
- // margin-top: 2.727rem;
-// }
-
-.osd-bg {
- min-width: 8.864rem;
-}
-
-.osd-value {
- @include elevation-border;
- @include elevation2;
- @include full-rounding;
- background-color: $layer0;
- padding: 0.341rem 1.023rem 0.341rem 0.682rem;
- min-width: 9.545rem;
-}
-
-.osd-progress {
- min-height: 0.682rem;
- min-width: 8.182rem;
- padding: 0rem;
- border-radius: 10rem;
- @include fluent_decel;
-
- trough {
- min-height: 0.682rem;
- min-width: 8.182rem;
- border-radius: 10rem;
- background-color: $layer2;
- // border: 0.068rem solid $onSecondaryContainer;
- }
-
- progress {
- @include fluent_decel;
- min-height: 0.409rem;
- min-width: 0.409rem;
- margin: 0rem 0.137rem;
- border-radius: 10rem;
- background-color: $onLayer2;
- }
-}
-
-.osd-label {
- font-size: 1.023rem;
- font-weight: 500;
-}
-
-.osd-value-txt {
- font-size: 1.023rem;
- font-weight: 500;
- color: $onLayer0;
-}
-
-.osd-brightness {
- color: $brightnessOnLayer0;
-}
-.osd-brightness-progress {
- progress {
- background-color: $brightnessOnLayer0;
- }
-}
-.osd-volume {
- color: $volumeOnLayer0;
-}
-.osd-volume-progress {
- progress {
- background-color: $volumeOnLayer0;
- }
-}
-
-.osd-notifs {
- padding-top: 0.313rem;
-}
-
-.osd-colorscheme {
- border-radius: 1.023rem;
- background-color: $layer0;
- padding: 0.313rem 0.626rem;
- @include elevation2;
-}
-
-.osd-colorscheme-settings {
- background-color: $layer1;
- padding: 0.313rem 0.626rem;
- @include small-rounding;
-}
-
-.osd-color {
- border-radius: 0.650rem;
- -gtk-outline-radius: 0.650rem;
- min-width: 2.727rem;
- min-height: 1.705rem;
- padding: 0rem 0.341rem;
- font-weight: bold;
-
- box {
- @include small-rounding;
- margin: 0.409rem;
- }
-}
-
-.osd-color-primary {
- background-color: $primary;
- color: $onPrimary;
- box { background-color: $onPrimary; }
-}
-.osd-color-primaryContainer {
- background-color: $primaryContainer;
- color: $onPrimaryContainer;
- box { background-color: $onPrimaryContainer; }
-}
-.osd-color-secondary {
- background-color: $secondary;
- color: $onSecondary;
- box { background-color: $onSecondary; }
-}
-.osd-color-secondaryContainer {
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
- box { background-color: $onSecondaryContainer; }
-}
-
-.osd-color-tertiary {
- background-color: $tertiary;
- color: $onTertiary;
- box { background-color: $onTertiary; }
-}
-.osd-color-tertiaryContainer {
- background-color: $tertiaryContainer;
- color: $onTertiaryContainer;
- box { background-color: $onTertiaryContainer; }
-}
-
-.osd-color-error {
- background-color: $error;
- color: $onError;
- box { background-color: $onError; }
-}
-.osd-color-errorContainer {
- background-color: $errorContainer;
- color: $onErrorContainer;
- box { background-color: $onErrorContainer; }
-}
-
-.osd-color-surface {
- background-color: $surface;
- color: $onSurface;
- border: 0.068rem solid $outlineVariant;
- box { background-color: $onSurface; }
-}
-
-.osd-color-surfaceContainer {
- background-color: $surfaceContainer;
- color: $onSurface;
- box { background-color: $onSurface; }
-}
-
-.osd-color-inverseSurface {
- background-color: $inverseSurface;
- color: $inverseOnSurface;
- box { background-color: $onSurfaceVariant; }
-}
-
-.osd-color-surfaceVariant {
- background-color: $surfaceVariant;
- color: $onSurfaceVariant;
- box { background-color: $onSurfaceVariant; }
-}
-.osd-color-L1 {
- background-color: $layer1;
- color: $onLayer1;
- box { background-color: $onLayer1; }
-}
-
-.osd-color-layer0 {
- background-color: $layer0;
- color: $onLayer0;
- box { background-color: $onLayer0; }
-}
-
-.osd-settings-btn-arrow {
- @include full-rounding;
- @include icon-material;
- min-width: 1.705rem;
- min-height: 1.705rem;
- color: $onSurface;
-
- &:hover {
- background-color: $surfaceContainerHigh;
- }
- &:active {
- background-color: $surfaceContainerHighest;
- }
-}
-
-.osd-show {
- transition: 200ms cubic-bezier(0.1, 1, 0, 1);
-}
-
-.osd-hide {
- transition: 190ms cubic-bezier(0.85, 0, 0.15, 1);
-}
diff --git a/.config/ags/scss/_osk.scss b/.config/ags/scss/_osk.scss
deleted file mode 100644
index 6cefc4af2..000000000
--- a/.config/ags/scss/_osk.scss
+++ /dev/null
@@ -1,119 +0,0 @@
-$osk_key_height: 2.5rem;
-$osk_key_width: 2.5rem;
-$osk_key_padding: 0.188rem;
-$osk_key_rounding: 0.545rem;
-$osk_key_fontsize: 1.091rem;
-
-.osk-window {
- // @include menu_decel_fast;
- @include large-rounding;
- @include elevation-border;
- @include elevation2;
- // min-height: 29.591rem;
- // min-width: 50rem;
- background-color: $layer0;
-}
-
-.osk-body {
- padding: 1.023rem;
- padding-top: 0rem;
-}
-
-.osk-show {
- @include menu_decel_fast;
-}
-
-.osk-hide {
- margin-top: 30.682rem;
- margin-bottom: -30.682rem;
- // opacity: 0;
- @include menu_accel_fast;
-}
-
-.osk-dragline {
- @include full-rounding;
- background-color: $onLayer0Inactive;
- min-height: 0.273rem;
- min-width: 10.227rem;
- margin-top: 0.545rem;
- margin-bottom: 0.205rem;
-}
-
-.osk-key {
- border-radius: $osk_key_rounding;
- background-color: $layer1;
- color: $onLayer1;
- padding: $osk_key_padding;
- font-weight: 500;
- font-size: $osk_key_fontsize;
-}
-
-.osk-key:hover,
-.osk-key:focus {
- background-color: $layer1Hover;
-}
-
-.osk-key:active {
- background-color: $layer1Active;
- font-size: $osk_key_fontsize;
-}
-
-.osk-key-active {
- background-color: $layer1Active;
-}
-
-.osk-key-normal {
- min-width: $osk_key_width;
- min-height: $osk_key_height;
-}
-
-.osk-key-fn {
- min-width: $osk_key_width * 1.005;
- min-height: calc($osk_key_height / 2); // dart-sass
- // min-height: $osk_key_height / 2; // sassc
-}
-
-.osk-key-tab {
- min-width: $osk_key_width * 1.6;
- min-height: $osk_key_height;
-}
-
-.osk-key-caps {
- min-width: $osk_key_width * 1.9;
- min-height: $osk_key_height;
-}
-
-.osk-key-shift {
- min-width: $osk_key_width * 2.5;
- min-height: $osk_key_height;
-}
-
-.osk-key-control {
- min-width: $osk_key_width * 1.3;
- min-height: $osk_key_height;
-}
-
-.osk-control-button {
- border-radius: $osk_key_rounding;
- background-color: $layer1;
- color: $onLayer1;
- font-weight: 500;
- font-size: $osk_key_fontsize;
- padding: 0.682rem;
-}
-
-.osk-control-button:hover,
-.osk-control-button:focus {
- background-color: $layer1Hover;
-}
-
-.osk-control-button:active {
- background-color: $layer1Active;
- font-size: $osk_key_fontsize;
-}
-
-.osk-key-empty, .osk-key-empty:hover, .osk-key-empty:focus {
- min-width: $osk_key_width;
- min-height: $osk_key_height;
- background-color: transparent;
-}
diff --git a/.config/ags/scss/_overview.scss b/.config/ags/scss/_overview.scss
deleted file mode 100644
index 1ba52c3ed..000000000
--- a/.config/ags/scss/_overview.scss
+++ /dev/null
@@ -1,139 +0,0 @@
-.overview-window {
- margin-top: 2.727rem;
-}
-
-.overview-search-box {
- @include element_decel;
- @include large-rounding;
- @include elevation-border;
- @include elevation2;
- min-width: 13.636rem;
- min-height: 3.409rem;
- padding: 0rem 1.364rem;
- padding-right: 2.864rem;
- background-color: $background;
- color: $onBackground;
-
- selection {
- background-color: $secondary;
- color: $onSecondary;
- }
-
- caret-color: transparent;
-}
-
-.overview-search-box-extended {
- min-width: 25.909rem;
- caret-color: $onSecondaryContainer;
-}
-
-.overview-search-prompt {
- color: $subtext;
-}
-
-.overview-search-icon {
- margin: 0rem 1.023rem;
-}
-
-.overview-search-prompt-box {
- margin-left: -18.545rem;
- margin-right: $elevation_margin + 0.068rem;
-}
-
-.overview-search-icon-box {
- margin-left: -18.545rem;
- margin-right: $elevation_margin + 0.068rem;
-}
-
-.overview-search-results {
- // min-height: 2.813rem;
- // min-height: 37.5rem;
- @include large-rounding;
- @include elevation-border;
- @include elevation2;
- min-width: 28.773rem;
- padding: 0.682rem;
- background-color: $layer0;
- color: $onLayer0;
-}
-
-.overview-search-results-icon {
- margin: 0rem 0.682rem;
- font-size: 2.386rem;
- min-width: 2.386rem;
- min-height: 2.386rem;
-}
-
-.overview-search-results-txt {
- margin-right: 0.682rem;
-}
-
-.overview-search-results-txt-cmd {
- margin-right: 0.682rem;
- @include techfont;
- font-size: 1.227rem;
-}
-
-.overview-search-result-btn {
- @include normal-rounding;
- padding: 0.341rem;
- min-width: 2.386rem;
- min-height: 2.386rem;
-
- caret-color: transparent;
-}
-
-.overview-search-result-btn:hover,
-.overview-search-result-btn:focus {
- background-color: $layer2;
-}
-
-.overview-search-result-btn:active {
- background-color: $layer2Hover;
-}
-
-.overview-tasks {
- @include large-rounding;
- @include elevation-border;
- @include elevation2;
- padding: 0.341rem;
- background-color: $background;
- color: $onBackground;
-}
-
-.overview-tasks-workspace {
- @include normal-rounding;
- // @include elevation-border;
- margin: 0.341rem;
- background-color: $layer1;
-}
-
-.overview-tasks-workspace-number {
- @include mainfont;
- color: $onSurfaceVariant;
-}
-
-.overview-tasks-window {
- @include normal-rounding;
- @include menu_decel;
- background-color: transparentize($layer3, 0.2);
- color: $onSurface;
- border: 0.068rem solid $surfaceContainerHighest;
-}
-
-.overview-tasks-window:hover,
-.overview-tasks-window:focus {
- background-color: transparentize($secondaryContainer, 0.3);
-}
-
-.overview-tasks-window:active {
- background-color: transparentize($secondaryContainer, 0);
-}
-
-.overview-tasks-window-selected {
- background-color: transparentize($secondaryContainer, 0.3);
-}
-
-.overview-tasks-window-dragging {
- opacity: 0.2;
-}
diff --git a/.config/ags/scss/_session.scss b/.config/ags/scss/_session.scss
deleted file mode 100644
index 163908294..000000000
--- a/.config/ags/scss/_session.scss
+++ /dev/null
@@ -1,40 +0,0 @@
-.session-bg {
- background-color: transparentize($color: $layer0, $amount: 0.4);
-}
-
-.session-button {
- @include large-rounding;
- min-width: 8.182rem;
- min-height: 8.182rem;
- background-color: $layer1;
- color: $onLayer1;
- font-size: 3rem;
-}
-
-.session-button-focused {
- background-color: $layer1Hover;
-}
-
-.session-button-desc {
- background-color: $layer2;
- color: $onLayer2;
- border-bottom-left-radius: $rounding_large;
- border-bottom-right-radius: $rounding_large;
- padding: 0.205rem 0.341rem;
- font-weight: 700;
-}
-
-.session-button-cancel {
- @include large-rounding;
- min-width: 8.182rem;
- min-height: 5.455rem;
- background-color: $layer1;
- color: $onLayer1;
- font-size: 3rem;
-}
-
-@for $i from 1 through 7 {
- .session-color-#{$i} {
- color: nth($sessionColors, $i);
- }
-}
diff --git a/.config/ags/scss/_sidebars.scss b/.config/ags/scss/_sidebars.scss
deleted file mode 100644
index c12bd44b2..000000000
--- a/.config/ags/scss/_sidebars.scss
+++ /dev/null
@@ -1,1154 +0,0 @@
-$sidebar_chat_textboxareaColor: mix($onSurfaceVariant, $surfaceVariant, 40%);
-
-@mixin group-padding {
- padding: 0.341rem;
-}
-
-.sidebar-right {
- @include menu_decel;
- @include elevation-border;
- @include elevation2;
- border-radius: $rounding_large - $elevation_margin + 0.068rem;
- min-width: 27.818rem;
- background-color: $background;
- padding: 1.023rem;
-}
-
-.sidebar-left {
- @include menu_decel;
- @include elevation-border;
- @include elevation2;
- border-radius: $rounding_large - $elevation_margin + 0.068rem;
- min-width: 27.818rem;
- background-color: $background;
- padding: 1.023rem;
-}
-
-.sidebar-group {
- @include normal-rounding;
- @include group-padding;
- background-color: $layer1;
-}
-
-.sidebar-group-nopad {
- @include normal-rounding;
- background-color: $layer1;
-}
-
-.sidebar-group-invisible {
- @include group-padding;
-}
-
-.sidebar-group-invisible-morehorizpad {
- padding: 0.341rem 0.682rem;
-}
-
-.sidebar-togglesbox {
- @include full-rounding;
- @include group-padding;
- background-color: $layer1;
-}
-
-.sidebar-iconbutton {
- @include full-rounding;
- @include element_decel;
- color: $onSurface;
- min-width: 2.727rem;
- min-height: 2.727rem;
-}
-
-.sidebar-iconbutton:hover,
-.sidebar-iconbutton:focus {
- background-color: $layer1Hover;
-}
-
-.sidebar-iconbutton:active {
- background-color: $layer1Active;
-}
-
-.sidebar-button-active {
- background-color: $primary;
- color: $onPrimary;
-}
-
-.sidebar-button-active:hover,
-.sidebar-button-active:focus {
- background-color: mix($primary, $layer1Hover, 70%);
-}
-
-.sidebar-button-active:active {
- background-color: mix($primary, $layer1Active, 40%);
-}
-
-.sidebar-buttons-separator {
- min-width: 0.068rem;
- min-height: 0.068rem;
- background-color: $onSurfaceVariant;
-}
-
-.sidebar-navrail {
- padding: 0rem $rounding_medium;
-}
-
-.sidebar-navrail-btn>box>label {
- @include full-rounding;
- @include menu_decel;
-}
-
-.sidebar-navrail-btn:hover>box>label:first-child,
-.sidebar-navrail-btn:focus>box>label:first-child {
- background-color: $layer1Hover;
-}
-
-.sidebar-navrail-btn:active>box>label:first-child {
- background-color: $layer1Active;
-}
-
-.sidebar-navrail-btn-active>box>label:first-child {
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
-}
-
-.sidebar-navrail-btn-active:hover>box>label:first-child,
-.sidebar-navrail-btn-active:focus>box>label:first-child {
- background-color: mix($secondaryContainer, $layer1Hover, 90%);
- color: mix($onSecondaryContainer, $layer1Hover, 90%);
-}
-
-.sidebar-sysinfo-grouppad {
- padding: 1.159rem;
-}
-
-.sidebar-memory-ram-circprog {
- @include fluent_decel_long;
- min-width: $rounding_small;
- min-height: 4.091rem;
- padding: 0.409rem;
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
- font-size: 0px;
-}
-
-.sidebar-memory-swap-circprog {
- @include fluent_decel_long;
- min-width: $rounding_small;
- min-height: 2.255rem;
- padding: 0.409rem;
- margin: 0.918rem;
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
- font-size: 0px;
-}
-
-.sidebar-cpu-circprog {
- min-width: $rounding_small;
- min-height: 3.409rem;
- padding: 0.409rem;
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
- @include fluent_decel_long;
- font-size: 0px;
-}
-
-.sidebar-scrollbar {
- trough {
- @include full-rounding;
- min-width: 0.545rem;
- background-color: transparent;
- }
-
- slider {
- @include full-rounding;
- @include element_decel;
- min-width: 0.273rem;
- min-height: 2.045rem;
- background-color: transparentize($onSurfaceVariant, 0.7);
- }
-
- slider:hover,
- slider:focus {
- background-color: transparentize($onSurfaceVariant, 0.6);
- }
-
- slider:active {
- background-color: transparentize($onSurface, 0.5);
- }
-}
-
-.sidebar-calendar-btn-arrow {
- @include full-rounding;
- background-color: $layer2;
- min-width: 1.705rem;
- min-height: 1.705rem;
-
- &:hover,
- &:focus {
- background-color: $layer2Hover;
- }
-
- &:active {
- background-color: $layer2Active;
- }
-}
-
-.sidebar-calendar-btn {
- @include full-rounding;
- @include element_decel;
- min-height: 2.523rem;
- min-width: 2.523rem;
- color: $onSurface;
-}
-
-.sidebar-calendar-btn:hover,
-.sidebar-calendar-btn:focus {
- background-color: $hovercolor;
-}
-
-.sidebar-calendar-btn:active {
- background-color: $activecolor;
-}
-
-.sidebar-calendar-btn-txt {
- margin-left: -10.341rem;
- margin-right: -10.341rem;
-}
-
-.sidebar-calendar-btn-today {
- background-color: $primary;
- color: $onPrimary;
-}
-
-.sidebar-calendar-btn-today:hover,
-.sidebar-calendar-btn-today:focus {
- background-color: mix($primary, $hovercolor, 70%);
-}
-
-.sidebar-calendar-btn-today:active {
- background-color: mix($primary, $hovercolor, 40%);
-}
-
-.sidebar-calendar-btn-othermonth {
- color: $outline;
-}
-
-.sidebar-calendar-header {
- margin: 0.341rem;
-}
-
-.sidebar-calendar-monthyear-btn {
- @include full-rounding;
- @include element_decel;
- padding: 0rem 0.682rem;
- background-color: $layer2;
- color: $onSurface;
-}
-
-.sidebar-calendar-monthyear-btn:hover,
-.sidebar-calendar-monthyear-btn:focus {
- background-color: $hovercolor;
-}
-
-.sidebar-calendar-monthyear-btn:active {
- background-color: $activecolor;
-}
-
-.sidebar-calendar-monthshift-btn {
- @include full-rounding;
- @include element_decel;
- min-width: 2.045rem;
- min-height: 2.045rem;
- background-color: $layer2;
- color: $outline;
-}
-
-.sidebar-calendar-monthshift-btn:hover {
- background-color: $hovercolor;
-}
-
-.sidebar-calendar-monthshift-btn:active {
- background-color: $activecolor;
-}
-
-.sidebar-calendar-collapsed-pill {
- @include full-rounding;
- background-color: $layer2;
- min-width: 1.705rem;
- min-height: 1.705rem;
- padding-left: 0.341rem;
- padding-right: 0.341rem;
-
- &:hover,
- &:focus {
- background-color: $layer2Hover;
- }
-
- &:active {
- background-color: $layer2Active;
- }
-}
-
-.sidebar-todo-item {
- @include small-rounding;
- margin-right: 0.545rem;
- // padding: 0.341rem;
- background-color: $layer2;
- color: $onLayer2;
-}
-
-.sidebar-todo-txt {
- margin: 0.682rem;
- margin-bottom: 0rem;
-}
-
-.sidebar-todo-actions {
- margin: 0.341rem;
- margin-top: 0rem;
- margin-right: 0rem;
-}
-
-.sidebar-todo-item-action {
- @include element_decel;
- border-radius: 9999px;
- min-width: 1.705rem;
- min-height: 1.705rem;
-}
-
-.sidebar-todo-item-action:hover,
-.sidebar-todo-item-action:focus {
- background-color: $layer2Hover;
-}
-
-.sidebar-todo-item-action:active {
- background-color: $layer2Active;
-}
-
-.sidebar-todo-crosser {
- transition: margin 200ms cubic-bezier(0.1, 1, 0, 1), background-color 0ms;
- min-width: 0rem;
-}
-
-.sidebar-todo-crosser-crossed {
- background-color: $onBackground;
-}
-
-.sidebar-todo-crosser-removed {
- background-color: $error;
-}
-
-.sidebar-todo-new {
- @include full-rounding;
- @include element_decel;
- background-color: $layer2;
- color: $onLayer2;
- margin: 0.341rem;
- padding: 0.205rem 0.545rem;
-}
-
-.sidebar-todo-new,
-.sidebar-todo-new:focus {
- color: $onSecondaryContainer;
- background-color: $secondaryContainer;
-}
-
-.sidebar-todo-new:active {
- color: $onPrimaryContainer;
- background-color: $primaryContainer;
-}
-
-.sidebar-todo-add {
- @include element_decel;
- @include small-rounding;
- min-width: 1.705rem;
- min-height: 1.705rem;
- color: $onSecondaryContainer;
- border: 0.068rem solid $onSurface;
-}
-
-.sidebar-todo-add:hover,
-.sidebar-todo-add:focus {
- background-color: $surfaceContainerHigh;
-}
-
-.sidebar-todo-add:active {
- background-color: $surfaceContainerHighest;
-}
-
-.sidebar-todo-add-available {
- @include element_decel;
- @include small-rounding;
- min-width: 1.705rem;
- min-height: 1.705rem;
- background-color: $primary;
- color: $onPrimary;
- border: 0.068rem solid $primary;
-}
-
-.sidebar-todo-add-available:hover,
-.sidebar-todo-add-available:focus {
- background-color: mix($primary, $hovercolor, 70%);
-}
-
-.sidebar-todo-add-available:active {
- background-color: mix($primary, $hovercolor, 40%);
-}
-
-.sidebar-todo-entry {
- @include element_decel;
- @include small-rounding;
- background-color: $surfaceVariant;
- color: $onSurfaceVariant;
- caret-color: $onSurfaceVariant;
- margin: 0rem 0.341rem;
- min-height: 1.773rem;
- min-width: 0rem;
- padding: 0.205rem 0.682rem;
- border: 0.068rem solid $outline;
-}
-
-.sidebar-todo-entry:focus {
- border: 0.068rem solid $onSurfaceVariant;
-}
-
-.sidebar-module {
- @include normal-rounding;
- @include group-padding;
- background-color: $layer1;
- padding: 0.682rem;
-}
-
-.sidebar-module-btn-arrow {
- @include full-rounding;
- @include icon-material;
- min-width: 1.705rem;
- min-height: 1.705rem;
- background-color: $layer2;
-
- &:hover,
- &:focus {
- background-color: $layer2Hover;
- }
-
- &:active {
- background-color: $layer2Active;
- }
-}
-
-.sidebar-module-scripts-button {
- @include full-rounding;
- @include icon-material;
- background-color: $layer1;
- min-width: 1.705rem;
- min-height: 1.705rem;
-
- &:hover,
- &:focus {
- background-color: $layer1Hover;
- }
-
- &:active {
- background-color: $layer1Active;
- }
-}
-
-$colorpicker_rounding: 0.341rem;
-
-.sidebar-module-colorpicker-wrapper {
- padding: 0.341rem;
-}
-
-.sidebar-module-colorpicker-cursorwrapper {
- padding: 0.341rem 0.136rem;
-}
-
-.sidebar-module-colorpicker-hue {
- min-height: 13.636rem;
- min-width: 1.091rem;
- border-radius: $colorpicker_rounding;
-}
-
-.sidebar-module-colorpicker-hue-cursor {
- background-color: $onBackground;
- border: 0.136rem solid $onBackground;
- min-height: 0.136rem;
- margin-top: -0.136rem;
- border-radius: $colorpicker_rounding;
-}
-
-.sidebar-module-colorpicker-saturationandlightness-wrapper {
- padding: 0.341rem;
-}
-
-.sidebar-module-colorpicker-saturationandlightness {
- min-height: 13.636rem;
- min-width: 13.636rem;
- border-radius: $colorpicker_rounding;
-}
-
-.sidebar-module-colorpicker-saturationandlightness-cursorwrapper {
- padding: 0.341rem;
- margin-top: -0.409rem;
- margin-left: -0.409rem;
-}
-
-.sidebar-module-colorpicker-saturationandlightness-cursor {
- @include full-rounding;
- border: 0.136rem solid white;
- min-width: 0.682rem;
- min-height: 0.682rem;
- margin-top: -0.409rem;
- margin-left: -0.409rem;
-}
-
-.sidebar-module-colorpicker-result-area {
- padding: 0.341rem;
-}
-
-.sidebar-module-colorpicker-result-box {
- border-radius: $colorpicker_rounding;
- min-width: 2.045rem;
- min-height: 0.682rem;
- padding: 0.341rem;
-}
-
-.sidebar-module-csscalc-valuebox {
- @include small-rounding;
- padding: 0.477rem;
- background-color: $layer2;
- color: $onLayer2;
-}
-
-.sidebar-module-csscalc-valuebox-copybtn {
- @include verysmall-rounding;
- @include element_decel;
- min-width: 1.705rem;
- min-height: 1.705rem;
- background-color: $layer2;
- color: $onLayer2;
-
- &:hover,
- &:focus {
- background-color: $layer2Hover;
- }
-
- &:active {
- background-color: $layer2Active;
- }
-}
-
-.sidebar-icontabswitcher {
- @include full-rounding;
- @include group-padding;
- background-color: $layer1;
-}
-
-.sidebar-chat-providerswitcher {
- @include small-rounding;
- padding: 0.477rem 0.682rem;
- background-color: $surfaceContainerHigh;
- color: $onSurfaceVariant;
-}
-
-.sidebar-chat-viewport {
- @include element_decel;
- padding: 0.682rem 0rem;
-}
-
-.sidebar-chat-textarea {
- @include normal-rounding;
- background-color: $layer1;
- color: $onLayer1;
- padding: 0.682rem;
-}
-
-.sidebar-chat-entry {
- color: $onSurfaceVariant;
- caret-color: $onSurfaceVariant;
- min-height: 1.773rem;
- min-width: 0rem;
-}
-
-.sidebar-chat-wrapper {
- transition: 400ms cubic-bezier(0.1, 1, 0, 1);
-}
-
-.sidebar-chat-wrapper-extended {
- min-height: 7.500rem;
-}
-
-.sidebar-chat-send {
- @include element_decel;
- min-width: 1.705rem;
- min-height: 1.705rem;
- border-radius: $rounding_medium - 0.681rem;
-}
-
-.sidebar-chat-send:hover,
-.sidebar-chat-send:focus {
- background-color: $surfaceBright;
-}
-
-.sidebar-chat-send:active {
- background-color: $surfaceVariant;
-}
-
-.sidebar-chat-send-available {
- background-color: $primary;
- color: $onPrimary;
-}
-
-.sidebar-chat-send-available:hover,
-.sidebar-chat-send-available:focus {
- background-color: mix($primary, $hovercolor, 70%);
-}
-
-.sidebar-chat-send-available:active {
- background-color: mix($primary, $hovercolor, 40%);
-}
-
-.sidebar-chat-messagearea {
- margin: 0.341rem;
-}
-
-.sidebar-chat-message {
- @include normal-rounding;
- @include group-padding;
- background-color: $layer1;
-}
-
-$skeleton-accent: mix($secondary, $onSecondary, 50%);
-
-@keyframes sidebar-chat-message-skeletonline-anim {
- 0% {
- background-position: 175% 0%;
- }
-
- 100% {
- background-position: 50% 0%;
- }
-}
-
-.sidebar-chat-message-skeletonline {
- border-radius: $rounding_verysmall;
- min-height: 1.364rem;
- background-color: $layer2;
-}
-
-.sidebar-chat-message-skeletonline-offset0 {
- background-repeat: no-repeat;
- background: linear-gradient(to right, $layer3 0%, $skeleton-accent 25%, $layer3 50%, $layer3 100%);
- background-size: 500% 500%;
- animation: sidebar-chat-message-skeletonline-anim 2s linear;
- animation-iteration-count: infinite;
-}
-
-.sidebar-chat-message-skeletonline-offset1 {
- background-repeat: no-repeat;
- background: linear-gradient(to right, $layer3 0%, $layer3 50%, $skeleton-accent 75%, $layer3 100%);
- background-size: 500% 500%;
- animation: sidebar-chat-message-skeletonline-anim 2s linear;
- animation-iteration-count: infinite;
-}
-
-.sidebar-chat-message-skeletonline-offset2 {
- margin-right: 5.795rem;
- background-repeat: no-repeat;
- background: linear-gradient(to right, $layer3 0%, $layer3 25%, $skeleton-accent 50%, $layer3 75%, $layer3 100%);
- background-size: 500% 500%;
- animation: sidebar-chat-message-skeletonline-anim 2s linear;
- animation-iteration-count: infinite;
-}
-
-.sidebar-chat-indicator {
- @include element_decel;
- @include full-rounding;
- min-width: 0.136rem;
-}
-
-.sidebar-chat-indicator-waifu {
- @include element_decel;
- @include full-rounding;
- min-width: 0.136rem;
- background-color: $onBackground;
-}
-
-.sidebar-chat-name {
- @include titlefont;
- @include small-rounding;
- padding: 0.341rem 0.818rem;
- margin: 0.341rem;
- background-color: $layer2;
- color: $onLayer2;
-}
-
-.sidebar-chat-name-user {
- background-color: $layer2;
- color: $onLayer2;
-}
-
-.sidebar-chat-name-bot {
- background-color: $secondary;
- color: $onSecondary;
-}
-
-.sidebar-chat-name-system {
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
-}
-
-.sidebar-chat-txtblock {
- margin-left: -0.136rem;
- padding: 0.341rem;
- padding-left: 0.818rem;
-}
-
-.sidebar-chat-txtblock-think {
- margin-left: -0.136rem;
- padding: 0.682rem;
- padding-left: 1.159rem;
-}
-
-.sidebar-chat-thinkblock {
- @include small-rounding;
- background-color: $layer2;
- color: $onLayer3;
-}
-
-.sidebar-chat-thinkblock-icon {
- @include verysmall-rounding;
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
- min-width: 2.045rem;
- min-height: 2.045rem;
-}
-
-.sidebar-chat-thinkblock-btn-arrow {
- @include full-rounding;
- @include icon-material;
- min-width: 1.705rem;
- min-height: 1.705rem;
- background-color: $layer2;
-
- &:hover,
- &:focus {
- background-color: $layer2Hover;
- }
-
- &:active {
- background-color: $layer2Active;
- }
-}
-
-.sidebar-chat-txt {
- @include readingfont;
-}
-
-.sidebar-chat-latex {
- @include small-rounding;
- margin: 0rem 0.682rem;
- padding: 0.682rem;
- color: $onBackground;
-}
-
-.sidebar-chat-codeblock {
- @include normal-rounding;
- background-color: $layer2;
- color: $onLayer2;
- margin: 0rem 0.682rem;
-}
-
-.sidebar-chat-codeblock-topbar {
- @include mainfont;
- background-color: $layer3;
- color: $onLayer3;
- border-top-left-radius: $rounding_small;
- border-top-right-radius: $rounding_small;
- padding: 0.341rem 0.477rem;
-}
-
-.sidebar-chat-codeblock-topbar-txt {
- @include full-rounding;
- padding: 0.273rem;
-}
-
-.sidebar-chat-codeblock-topbar-btn {
- @include full-rounding;
- @include element_decel;
- padding: 0.273rem 0.477rem;
-}
-
-.sidebar-chat-codeblock-topbar-btn:hover,
-.sidebar-chat-codeblock-topbar-btn:focus {
- background-color: $surfaceBright;
-}
-
-.sidebar-chat-codeblock-topbar-btn:active {
- background-color: $surfaceVariant;
-}
-
-.sidebar-chat-codeblock-code {
- @include techfont;
- padding: 0.682rem;
-}
-
-.sidebar-chat-divider {
- min-height: 1px;
- background-color: $sidebar_chat_textboxareaColor;
- margin: 0rem 0.545rem;
-}
-
-.sidebar-chat-welcome-txt {
- margin: 0rem 3.409rem;
-}
-
-.sidebar-chat-settings-toggles {
- min-width: 16.705rem;
-}
-
-.sidebar-chat-welcome-icon {
- @include full-rounding;
- font-size: 4rem;
-}
-
-.sidebar-chat-welcome-logo {
- @include full-rounding;
- @include element_decel;
- @include icon-material;
- min-height: 4.773rem;
- min-width: 4.773rem;
- font-size: 3.076rem;
- background-color: $secondaryContainer;
- color: $onSecondaryContainer;
-}
-
-.sidebar-chat-chip {
- @include element_decel;
- @include small-rounding;
- padding: 0.341rem 0.477rem;
-}
-
-.sidebar-chat-chip-action {
- @include element_decel;
- background-color: $layer2;
- color: $onSurfaceVariant;
-}
-
-.sidebar-chat-chip-action:hover,
-.sidebar-chat-chip-action:focus {
- background-color: $hovercolor;
-}
-
-.sidebar-chat-chip-action:active {
- background-color: $activecolor;
-}
-
-.sidebar-chat-chip-action-active {
- color: $sidebar_chat_textboxareaColor;
- border: 0.068rem solid $sidebar_chat_textboxareaColor;
-}
-
-.sidebar-chat-chip-toggle {
- @include element_decel;
- @include small-rounding;
- padding: 0.341rem 0.477rem;
- background-color: $layer3;
- color: $onSurfaceVariant;
-}
-
-.sidebar-chat-chip-toggle:focus,
-.sidebar-chat-chip-toggle:hover {
- background-color: $hovercolor;
-}
-
-.sidebar-chat-chip-toggle:active {
- background-color: $activecolor;
-}
-
-.sidebar-controlbtn {
- @include small-rounding;
- @include element_decel;
- min-height: 2.386rem;
- min-width: 2.386rem;
- color: $onSurface;
-}
-
-.sidebar-controlbtn:hover,
-.sidebar-controlbtn:focus {
- background-color: $hovercolor;
-}
-
-.sidebar-controlbtn:active {
- background-color: $activecolor;
-}
-
-.sidebar-controlbtn-enabled {
- background-color: $secondaryContainer;
-
- label {
- color: $onSecondaryContainer;
- }
-}
-
-.sidebar-controlbtn-enabled:hover,
-.sidebar-controlbtn-enabled:focus {
- background-color: mix($secondaryContainer, $onSecondaryContainer, 90%);
-}
-
-.sidebar-controlbtn-enabled:active {
- background-color: mix($secondaryContainer, $onSecondaryContainer, 75%);
-}
-
-.sidebar-expandbtn-enabled {
- min-width: 29.113rem;
-}
-
-.sidebar-waifu-heading {
- @include titlefont;
- padding: 0.341rem;
- margin-left: -0.136rem;
- padding-left: 0.818rem;
-}
-
-.sidebar-waifu-txt {
- @include mainfont;
-}
-
-.sidebar-waifu-image {
- @include normal-rounding;
- background-size: cover;
- background-repeat: no-repeat;
- background-position: center;
-}
-
-.sidebar-waifu-image-actions {
- @include element_decel;
- padding: 0.313rem;
-}
-
-$waifu_image_overlay_transparency: 0.7;
-
-.sidebar-waifu-image-action {
- @include full-rounding;
- min-width: 1.875rem;
- min-height: 1.875rem;
- background-color: rgba(0, 0, 0, $waifu_image_overlay_transparency ); // Fixed cuz on image
- color: rgba(255, 255, 255, $waifu_image_overlay_transparency);
-}
-
-.sidebar-waifu-image-action:hover,
-.sidebar-waifu-image-action:focus {
- background-color: rgba(30, 30, 30, $waifu_image_overlay_transparency);
-}
-
-.sidebar-waifu-image-action:active {
- background-color: rgba(60, 60, 60, $waifu_image_overlay_transparency);
-}
-
-.sidebar-booru-provider {
- @include titlefont;
- @include small-rounding;
- padding: 0.341rem 0.818rem;
- margin: 0.341rem;
- margin-bottom: 0rem;
- font-weight: bold;
- background-color: $primary;
- color: $onPrimary;
-}
-
-.sidebar-booru-imagegrid {
- @include normal-rounding;
-}
-
-.sidebar-booru-image {
- @include small-rounding;
- margin: 0.273rem;
- min-width: 11.932rem;
-}
-
-.sidebar-booru-image-drawingarea {
- @include small-rounding;
- min-width: 12.273rem;
- min-height: 12.273rem;
-}
-
-.sidebar-booru-image-actions {
- @include element_decel;
- margin: 0.545rem;
-}
-
-.sidebar-booru-tip-icon {
- min-width: 2.392rem;
- min-height: 2.392rem;
-}
-
-.sidebar-volmixer-stream {
- border-bottom: 0.068rem solid $outlineVariant;
- padding: 0.682rem;
- color: $onSurface;
-}
-
-.sidebar-volmixer-stream-appicon {
- font-size: 3.273rem;
-}
-
-.sidebar-volmixer-stream-slider {
- trough {
- border-radius: $rounding_verysmall;
- min-height: 1.364rem;
- min-width: 1.364rem;
- background-color: $secondaryContainer;
- }
-
- highlight {
- border-radius: $rounding_verysmall;
- min-height: 1.364rem;
- min-width: 1.364rem;
- background-color: $primary;
- }
-
- slider {
- border-radius: $rounding_verysmall;
- min-height: 1.364rem;
- min-width: 1.364rem;
- }
-}
-
-.sidebar-volmixer-status {
- color: $onSurface;
- margin: 0rem 0.682rem;
-}
-
-.sidebar-volmixer-deviceselector {
- @include small-rounding;
- padding: 0.477rem 0.682rem;
- background-color: $surfaceContainerHigh;
- color: $onSurfaceVariant;
-}
-
-.sidebar-bluetooth-device {
- padding: 0.682rem;
- @include normal-rounding;
- background-color: $layer2;
- color: $onLayer2;
-}
-
-.sidebar-bluetooth-appicon {
- @include symbolic-icon;
- font-size: 2.045rem;
-}
-
-.sidebar-bluetooth-device-remove {
- @include full-rounding;
- min-width: 2.045rem;
- min-height: 2.045rem;
- // background-color: $layer3;
- padding: 0.341rem;
-}
-
-.sidebar-bluetooth-device-remove:hover,
-.sidebar-bluetooth-device-remove:focus {
- @include full-rounding;
- background-color: $layer2Hover;
- padding: 0.341rem;
-}
-
-.sidebar-wifinetworks-network {
- padding: 0.682rem;
- @include normal-rounding;
- background-color: $layer2;
- color: $onLayer2;
-}
-
-.sidebar-wifinetworks-network:hover,
-.sidebar-wifinetworks-network:focus {
- background-color: $layer2Hover;
-}
-
-.sidebar-wifinetworks-network:active {
- background-color: $layer2Active;
-}
-
-.sidebar-wifinetworks-signal {
- @include symbolic-icon;
- font-size: 2.045rem;
-}
-
-.sidebar-wifinetworks-auth-box {
- @include small-rounding;
- background-color: $layer1;
- color: $onLayer1;
-}
-
-.sidebar-wifinetworks-auth-entry {
- @include small-rounding;
- color: $onLayer1;
- padding: 0.682rem;
- caret-color: $onLayer2;
-}
-
-.sidebar-wifinetworks-auth-visible {
- @include element_decel;
- @include small-rounding;
- min-width: 2.045rem;
- min-height: 2.045rem;
- margin: 0.341rem;
-
- &:hover,
- &:focus {
- background-color: $layer3Hover;
- }
-
- &:active {
- background-color: $layer3Active;
- }
-}
-
-.sidebar-wifinetworks-bandwidth {
- min-width: 6.3rem;
- padding-left: 1rem;
-}
-
-.sidebar-centermodules-bottombar-button {
- @include full-rounding;
- @include element_decel;
- min-width: 6.818rem;
- min-height: 2.25rem;
- background-color: $layer2;
- color: $onLayer2;
-}
-
-.sidebar-centermodules-bottombar-button:hover,
-.sidebar-centermodules-bottombar-button:focus {
- background-color: $layer2Hover;
-}
-
-.sidebar-centermodules-bottombar-button:active {
- background-color: $layer2Active;
-}
-
-.sidebar-centermodules-scrollgradient-bottom {
- @if $transparent ==False {
- background: linear-gradient(to top, $layer1 0%, transparentize($layer1, 1) 1.023rem);
- }
-}
-
-.sidebar-centermodules-scrollgradient-bottom-contentmargin {
- margin-bottom: 1.023rem;
-}
-
-.sidebar-wifinetworks-network-button {
- @include full-rounding;
- @include element_decel;
- min-width: 6.818rem;
- min-height: 2.25rem;
- color: $onLayer3;
- background-color: $layer3;
-
- &:hover,
- &:focus {
- background-color: $layer3Hover;
- }
-
- &:active {
- background-color: $layer3Active;
- }
-}
\ No newline at end of file
diff --git a/.config/ags/scss/_wal.scss b/.config/ags/scss/_wal.scss
deleted file mode 100644
index 50ec8e5ab..000000000
--- a/.config/ags/scss/_wal.scss
+++ /dev/null
@@ -1,8 +0,0 @@
-// To prevent errors
-$color1: $surfaceVariant;
-$color2: $surfaceVariant;
-$color3: $surfaceVariant;
-$color4: $secondaryContainer;
-$color5: $secondaryContainer;
-$color6: $secondaryContainer;
-$color7: $onBackground;
\ No newline at end of file
diff --git a/.config/ags/scss/fallback/_material.scss b/.config/ags/scss/fallback/_material.scss
deleted file mode 100644
index 7f6294abd..000000000
--- a/.config/ags/scss/fallback/_material.scss
+++ /dev/null
@@ -1,76 +0,0 @@
-$darkmode: True;
-$transparent: False;
-$primary_paletteKeyColor: #02DCFF;
-$secondary_paletteKeyColor: #597B8F;
-$tertiary_paletteKeyColor: #557AA1;
-$neutral_paletteKeyColor: #6D797D;
-$neutral_variant_paletteKeyColor: #6A7A7F;
-$background: #091518;
-$onBackground: #D8E5E9;
-$surface: #091518;
-$surfaceDim: #091518;
-$surfaceBright: #2F3B3F;
-$surfaceContainerLowest: #051013;
-$surfaceContainerLow: #121D21;
-$surfaceContainer: #162125;
-$surfaceContainerHigh: #202C2F;
-$surfaceContainerHighest: #2B373A;
-$onSurface: #D8E5E9;
-$surfaceVariant: #3A494E;
-$onSurfaceVariant: #B9C9CE;
-$inverseSurface: #D8E5E9;
-$inverseOnSurface: #273236;
-$outline: #839398;
-$outlineVariant: #3A494E;
-$shadow: #000000;
-$scrim: #000000;
-$surfaceTint: #00D9FC;
-$primary: #00D9FC;
-$onPrimary: #003640;
-$primaryContainer: #004E5C;
-$onPrimaryContainer: #AAEDFF;
-$inversePrimary: #006879;
-$secondary: #A8CBE2;
-$onSecondary: #0D3446;
-$secondaryContainer: #2A4D60;
-$onSecondaryContainer: #C7E9FF;
-$tertiary: #A4CAF5;
-$onTertiary: #003256;
-$tertiaryContainer: #6F94BC;
-$onTertiaryContainer: #000000;
-$error: #FFB4AB;
-$onError: #690005;
-$errorContainer: #93000A;
-$onErrorContainer: #FFDAD6;
-$primaryFixed: #AAEDFF;
-$primaryFixedDim: #00D9FC;
-$onPrimaryFixed: #001F26;
-$onPrimaryFixedVariant: #004E5C;
-$secondaryFixed: #C4E7FF;
-$secondaryFixedDim: #A8CBE2;
-$onSecondaryFixed: #001E2C;
-$onSecondaryFixedVariant: #284B5D;
-$tertiaryFixed: #D0E4FF;
-$tertiaryFixedDim: #A4CAF5;
-$onTertiaryFixed: #001D34;
-$onTertiaryFixedVariant: #21496E;
-$success: #B5CCBA;
-$onSuccess: #213528;
-$successContainer: #374B3E;
-$onSuccessContainer: #D1E9D6;
-$term0: #0E1C21;
-$term1: #8383FF;
-$term2: #63DEDB;
-$term3: #75FCDD;
-$term4: #78B4C1;
-$term5: #7AAEEA;
-$term6: #81D7DE;
-$term7: #CCDBD5;
-$term8: #B1BCB5;
-$term9: #BCB9FF;
-$term10: #F4FFFE;
-$term11: #FFFFFF;
-$term12: #BEE3E8;
-$term13: #C8DAFF;
-$term14: #EAFEFF;
-$term15: #B0ECFC;
diff --git a/.config/ags/scss/main.scss b/.config/ags/scss/main.scss
deleted file mode 100644
index 57938e81a..000000000
--- a/.config/ags/scss/main.scss
+++ /dev/null
@@ -1,42 +0,0 @@
-// Reset
-// * {
-// all: unset;
-// }
-*:not(popover) { all: unset; }
-
-// Colors
-@import 'material'; // Material colors
-@import './colors'; // Global color definitions. Uses material colors as base.
-@import './lib_mixins';
-@import 'lib_mixins_overrides';
-@import './lib_classes';
-@import './common'; // Context menu n stuff
-
-// Components
-@import './bar';
-@import './cheatsheet';
-@import './desktopbackground';
-@import './dock';
-@import './osd';
-@import './overview';
-@import './osk';
-@import './sidebars';
-@import './session';
-@import './notifications';
-
-// Music is put last as it might mess stuff up with pywal
-@import './music'; // Everything related to music is here
-
-// Classes for interaction
-.growingRadial {
- transition: 300ms cubic-bezier(0.2, 0.0, 0, 1.0);
-}
-.fadingRadial {
- transition: 50ms cubic-bezier(0.2, 0.0, 0, 1.0);
-}
-.sidebar-pinned {
- margin: 0rem;
- border-radius: 0rem;
- border-bottom-right-radius: $rounding_large;
- border: 0rem solid;
-}
diff --git a/.config/ags/services/booru.js b/.config/ags/services/booru.js
deleted file mode 100644
index b8dd98dce..000000000
--- a/.config/ags/services/booru.js
+++ /dev/null
@@ -1,156 +0,0 @@
-import Service from 'resource:///com/github/Aylur/ags/service.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-
-const APISERVICES = {
- 'yandere': {
- name: 'yande.re',
- endpoint: 'https://yande.re/post.json',
- },
- 'konachan': {
- name: 'Konachan',
- endpoint: 'https://konachan.net/post.json',
- },
-}
-
-const getWorkingImageSauce = (url) => {
- if (url.includes('pximg.net')) {
- return `https://www.pixiv.net/en/artworks/${url.substring(url.lastIndexOf('/') + 1).replace(/_p\d+\.(png|jpg|jpeg|gif)$/, '')}`;
- }
- return url;
-}
-
-function paramStringFromObj(params) {
- return Object.entries(params)
- .map(([key, value]) => {
- if (Array.isArray(value)) { // If it's an array, repeat
- if (value.length == 0) return '';
- let thisKey = `${encodeURIComponent(key)}=${encodeURIComponent(value[0])}`
- for (let i = 1; i < value.length; i++) {
- thisKey += `&${encodeURIComponent(key)}=${encodeURIComponent(value[i])}`;
- }
- return thisKey;
- }
- return `${key}=${value}`;
- })
- .join('&');
-}
-
-class BooruService extends Service {
- _baseUrl = 'https://yande.re/post.json';
- _mode = 'yandere';
- _nsfw = userOptions.sidebar.image.allowNsfw;
- _responses = [];
- _queries = [];
-
- static {
- Service.register(this, {
- 'initialized': [],
- 'clear': [],
- 'newResponse': ['int'],
- 'updateResponse': ['int'],
- }, {
- 'nsfw': ['boolean'],
- });
- }
-
- constructor() {
- super();
- this.emit('initialized');
- }
-
- clear() {
- this._responses = [];
- this._queries = [];
- this.emit('clear');
- }
-
- get nsfw() { return this._nsfw }
- set nsfw(value) { this._nsfw = value; this.notify('nsfw'); }
-
- get mode() { return this._mode }
- set mode(value) {
- this._mode = value;
- this._baseUrl = APISERVICES[this._mode].endpoint;
- }
- get providerName() {
- return APISERVICES[this._mode].name;
- }
- get queries() { return this._queries }
- get responses() { return this._responses }
-
- async fetch(msg) {
- // Init
- const userArgs = `${msg.replace('rating:safe', '')}${(!this._nsfw || msg.includes('safe')) ? ' rating:safe' : ''}`.split(/\s+/);
- // console.log(userArgs)
-
- let taglist = [];
- let page = 1;
- // Construct body/headers
- for (let i = 0; i < userArgs.length; i++) {
- const thisArg = userArgs[i].trim();
- if (thisArg.length == 0 || thisArg == '.' || thisArg.includes('*')) continue;
- else if (!isNaN(thisArg)) page = parseInt(thisArg);
- else taglist.push(thisArg);
- }
- const newMessageId = this._queries.length;
- this._queries.push({
- providerName: APISERVICES[this._mode].name,
- taglist: taglist.length == 0 ? ['*', `${page}`] : [...taglist, `${page}`],
- realTagList: taglist,
- page: page,
- });
- this.emit('newResponse', newMessageId);
- const params = {
- 'tags': taglist.join('+'),
- 'page': `${page}`,
- 'limit': `${userOptions.sidebar.image.batchCount}`,
- };
- const paramString = paramStringFromObj(params);
- // Fetch
- // Note: body isn't included since passing directly to url is more reliable
- const options = {
- method: 'GET',
- headers: APISERVICES[this._mode].headers,
- };
- let status = 0;
- // console.log(`${APISERVICES[this._mode].endpoint}?${paramString}`);
-
- Utils.fetch(`${APISERVICES[this._mode].endpoint}?${paramString}`, options)
- .then(result => {
- status = result.status;
- return result.text();
- })
- .then((dataString) => { // Store interesting stuff and emit
- // console.log(dataString);
- const parsedData = JSON.parse(dataString);
- // console.log(parsedData)
- this._responses[newMessageId] = parsedData.map(obj => {
- return {
- aspect_ratio: obj.width / obj.height,
- id: obj.id,
- tags: obj.tags,
- rating: obj.rating,
- is_nsfw: (obj.rating != 's'),
- md5: obj.md5,
- preview_url: obj.preview_url,
- preview_width: obj.preview_width,
- preview_height: obj.preview_height,
- sample_url: obj.sample_url,
- sample_width: obj.sample_width,
- sample_height: obj.sample_height,
- file_url: obj.file_url,
- file_ext: obj.file_ext,
- file_width: obj.file_width,
- file_height: obj.file_height,
- source: getWorkingImageSauce(obj.source),
- }
- });
- this.emit('updateResponse', newMessageId);
- })
- .catch(print);
-
- }
-}
-
-export default new BooruService();
-
diff --git a/.config/ags/services/brightness.js b/.config/ags/services/brightness.js
deleted file mode 100644
index 1800d162d..000000000
--- a/.config/ags/services/brightness.js
+++ /dev/null
@@ -1,170 +0,0 @@
-import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
-import Service from 'resource:///com/github/Aylur/ags/service.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { exec, execAsync } = Utils;
-
-import { clamp } from '../modules/.miscutils/mathfuncs.js';
-
-class BrightnessServiceBase extends Service {
- static {
- Service.register(
- this,
- { 'screen-changed': ['float'], },
- { 'screen-value': ['float', 'rw'], },
- );
- }
-
- _screenValue = 0;
-
- // the getter has to be in snake_case
- get screen_value() { return this._screenValue; }
-
- // the setter has to be in snake_case too
- set screen_value(percent) {
- percent = clamp(percent, 0, 1);
- this._screenValue = percent;
-
- Utils.execAsync(this.setBrightnessCmd(percent))
- .then(() => {
- // signals has to be explicity emitted
- this.emit('screen-changed', percent);
- this.notify('screen-value');
-
- // or use Service.changed(propName: string) which does the above two
- // this.changed('screen');
- })
- .catch(print);
- }
-
- // overwriting connectWidget method, lets you
- // change the default event that widgets connect to
- connectWidget(widget, callback, event = 'screen-changed') {
- super.connectWidget(widget, callback, event);
- }
-}
-
-class BrightnessCtlService extends BrightnessServiceBase {
- static {
- Service.register(this);
- }
-
- constructor() {
- super();
- const current = Number(exec('brightnessctl g'));
- const max = Number(exec('brightnessctl m'));
- this._screenValue = current / max;
- }
-
- setBrightnessCmd(percent) {
- return `brightnessctl s ${percent * 100}% -q`;
- }
-}
-
-class BrightnessDdcService extends BrightnessServiceBase {
- static {
- Service.register(this);
- }
-
- constructor(busNum) {
- super();
- this._busNum = busNum;
- Utils.execAsync(`ddcutil -b ${this._busNum} getvcp 10 --brief`)
- .then((out) => {
- // only the last line is useful
- out = out.split('\n');
- out = out[out.length - 1];
-
- out = out.split(' ');
- const current = Number(out[3]);
- const max = Number(out[4]);
- this._screenValue = current / max;
- })
- .catch(print);
- }
-
- setBrightnessCmd(percent) {
- return `ddcutil -b ${this._busNum} setvcp 10 ${Math.round(percent * 100)}`;
- }
-}
-
-async function listDdcMonitorsSnBus() {
- let ddcSnBus = {};
- try {
- // Its' better not to use --brief. This way if a serial number is not
- // found we can still use the binary serial number as an alternative
- const out = await Utils.execAsync('ddcutil detect');
- const displays = out.split('\n\n');
- displays.forEach(display => {
- const reg = /[Dd]isplay/;
- if (!reg.test(display)) {
- return;
- }
- const lines = display.split('\n');
- let sn, busNum;
- let unresponsive = false;
- for (let line of lines) {
- line = line.trim()
-
- // Sometimes ddcutils will report a DP monitor twice, one of the
- // two copies of the monitor will "not support DDC/CI". Just ignore it
- // See https://www.ddcutil.com/faq/#duplicate_displayport
- if (line.includes('unresponsive')) {
- unresponsive = true;
- }
- if (line.startsWith('Serial')) {
- sn = line.split(':')[1].trim();
- // Sometimes sn can be empty. In this cases let's relay on binary sn
- } else if (line.startsWith('Binary') && !sn) {
- // Make the serial number upper case except for the leading '0x' since Hyprland
- // seems to use upper case for the rest of the string and ddcutil uses
- // lower case for all the binary sn
- sn = '0x'+line.split('(')[1].slice(2,-1).toUpperCase();
- } else if (line.startsWith('I2C bus:')) {
- busNum = line.split('/dev/i2c-')[1];
- }
- }
- if (sn && busNum && !unresponsive){
- ddcSnBus[sn] = busNum;
- }
- });
- } catch (err) {
- }
- return ddcSnBus;
-}
-
-// Service instance
-const numMonitors = Hyprland.monitors.length;
-const service = Array(numMonitors);
-const ddcSnBus = await listDdcMonitorsSnBus();
-for (let i = 0; i < service.length; i++) {
- const monitorName = Hyprland.monitors[i].name;
- const monitorSn = Hyprland.monitors[i].serial;
- const preferredController = userOptions.brightness.controllers[monitorName]
- || userOptions.brightness.controllers.default || "auto";
- if (preferredController) {
- switch (preferredController) {
- case "brightnessctl":
- service[i] = new BrightnessCtlService();
- break;
- case "ddcutil":
- service[i] = new BrightnessDdcService(ddcSnBus[monitorSn]);
- break;
- case "auto":
- if (monitorSn in ddcSnBus && !!exec(`bash -c 'command -v ddcutil'`)){
- service[i] = new BrightnessDdcService(ddcSnBus[monitorSn]);
- }
- else {
- service[i] = new BrightnessCtlService();
- }
- break;
- default:
- throw new Error(`Unknown brightness controller ${preferredController}`);
- }
- }
-}
-
-// make it global for easy use with cli
-globalThis.brightness = service[0];
-
-// export to use in other modules
-export default service;
diff --git a/.config/ags/services/darkmode.js b/.config/ags/services/darkmode.js
deleted file mode 100644
index b0f54be3c..000000000
--- a/.config/ags/services/darkmode.js
+++ /dev/null
@@ -1,39 +0,0 @@
-const { Gio, GLib } = imports.gi;
-import Service from 'resource:///com/github/Aylur/ags/service.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-import { darkMode } from '../modules/.miscutils/system.js';
-const { exec, execAsync } = Utils;
-
-const timeBefore = (time1, time2) => { // Arrays of [hour, minute]
- if (time1[0] == time2[0]) return time1[1] < time2[1];
- return time1[0] < time2[0];
-}
-
-const timeSame = (time1, time2) => // Arrays of [hour, minute]
- (time1[0] == time2[0] && time1[1] == time2[1]);
-
-const timeBeforeOrSame = (time1, time2) => // Arrays of [hour, minute]
- (timeBefore(time1, time2) || timeSame(time1, time2));
-
-const timeInRange = (time, rangeStart, rangeEnd) => { // Arrays of [hour, minute]
- if (timeBefore(rangeStart, rangeEnd))
- return (timeBeforeOrSame(rangeStart, time) && timeBeforeOrSame(time, rangeEnd))
- else { // rangeEnd < rangeStart, meaning it ends the following day
- rangeEnd[0] += 24;
- if (timeBefore(time, rangeStart)) time[0] += 24;
- return (timeBeforeOrSame(rangeStart, time) && timeBeforeOrSame(time, rangeEnd))
- }
-
-}
-
-export async function startAutoDarkModeService() {
- Utils.interval(userOptions.time.interval, () => {
- if ((!userOptions.appearance.autoDarkMode.enabled)) return;
- const fromTime = (userOptions.appearance.autoDarkMode.from).split(':').map(Number);
- const toTime = (userOptions.appearance.autoDarkMode.to).split(':').map(Number);
- if (fromTime == toTime) return;
- const currentDateTime = GLib.DateTime.new_now_local();
- const currentTime = [currentDateTime.get_hour(), currentDateTime.get_minute()];
- darkMode.value = timeInRange(currentTime, fromTime, toTime);
- })
-}
diff --git a/.config/ags/services/gemini.js b/.config/ags/services/gemini.js
deleted file mode 100644
index 18921cce6e..000000000
--- a/.config/ags/services/gemini.js
+++ /dev/null
@@ -1,335 +0,0 @@
-import Service from 'resource:///com/github/Aylur/ags/service.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-
-import Gio from 'gi://Gio';
-import GLib from 'gi://GLib';
-import Soup from 'gi://Soup?version=3.0';
-import { fileExists } from '../modules/.miscutils/files.js';
-
-const HISTORY_DIR = `${GLib.get_user_state_dir()}/ags/user/ai/chats/`;
-const HISTORY_FILENAME = `gemini.txt`;
-const HISTORY_PATH = HISTORY_DIR + HISTORY_FILENAME;
-const initMessages =
- [
- { role: "user", parts: [{ text: "You are an assistant on a sidebar of a Wayland Linux desktop. Please always use a casual tone when answering your questions, unless requested otherwise or making writing suggestions. These are the steps you should take to respond to the user's queries:\n1. If it's a writing- or grammar-related question or a sentence in quotation marks, Please point out errors and correct when necessary using underlines, and make the writing more natural where appropriate without making too major changes. If you're given a sentence in quotes but is grammatically correct, explain briefly concepts that are uncommon.\n2. If it's a question about system tasks, give a bash command in a code block with brief explanation.\n3. Otherwise, when asked to summarize information or explaining concepts, you are should use bullet points and headings. For mathematics expressions, you *have to* use LaTeX within a code block with the language set as \"latex\". \nNote: Use casual language, be short, while ensuring the factual correctness of your response. If you are unsure or don’t have enough information to provide a confident answer, simply say “I don’t know” or “I’m not sure.”. \nThanks!" }], },
- { role: "model", parts: [{ text: "Got it!" }], },
- { role: "user", parts: [{ text: "\"He rushed to where the event was supposed to be hold, he didn't know it got canceled\"" }], },
- { role: "model", parts: [{ text: "## Grammar correction\nErrors:\n\"He rushed to where the event was supposed to be __hold____,__ he didn't know it got canceled\"\nCorrection + minor improvements:\n\"He rushed to the place where the event was supposed to be __held____, but__ he didn't know that it got canceled\"" }], },
- { role: "user", parts: [{ text: "raise volume by 5%" }], },
- { role: "model", parts: [{ text: "## Volume +5\n```bash\nwpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+\n```\nThis command uses the `wpctl` utility to adjust the volume of the default sink." }], }, { role: "user", parts: [{ text: "main advantages of the nixos operating system" }], },
- { role: "model", parts: [{ text: "## NixOS advantages\n- **Reproducible**: A config working on one device will also work on another\n- **Declarative**: One config language to rule them all. Effortlessly share them with others.\n- **Reliable**: Per-program software versioning. Mitigates the impact of software breakage" }], },
- { role: "user", parts: [{ text: "whats skeumorphism" }], },
- { role: "model", parts: [{ text: "## Skeuomorphism\n- A design philosophy- From early days of interface designing- Tries to imitate real-life objects- It's in fact still used by Apple in their icons until today." }], },
- { role: "user", parts: [{ text: "\"ignorance is bliss\"" }], },
- { role: "model", parts: [{ text: "## \"Ignorance is bliss\"\n- A Latin proverb that means being unaware of something negative can be a source of happiness\n- Often used to justify avoiding difficult truths or responsibilities\n- Can also be interpreted as a warning against seeking knowledge that may bring pain or sorrow" }], },
- { role: "user", parts: [{ text: "find the derivative of (x-438)/(x^2+23x-7)+x^x" }], },
- { role: "model", parts: [{ text: "## Derivative\n```latex\n\\[\n\\frac{d}{dx}\\left(\\frac{x - 438}{x^2 + 23x - 7} + x^x\\right) = \\frac{-(x^2+23x-7)-(x-438)(2x+23)}{(x^2+23x-7)^2} + x^x(\\ln(x) + 1)\n\\]\n```" }], },
- { role: "user", parts: [{ text: "write the double angle formulas" }], },
- { role: "model", parts: [{ text: "## Double angle formulas\n```latex\n\\[\n\\sin(2\theta) = 2\\sin(\\theta)\\cos(\\theta)\n\\]\n\\\\\n\\[\n\\cos(2\\theta) = \\cos^2(\\theta) - \\sin^2(\\theta)\n\\]\n\\\\\n\\[\n\\tan(2\theta) = \\frac{2\\tan(\\theta)}{1 - \\tan^2(\\theta)}\n\\]\n```" }], },
- ];
-
-
-if (!fileExists(`${GLib.get_user_config_dir()}/gemini_history.json`)) {
- Utils.execAsync([`bash`, `-c`, `touch ${GLib.get_user_config_dir()}/gemini_history.json`]).catch(print);
- Utils.writeFile('[ ]', `${GLib.get_user_config_dir()}/gemini_history.json`).catch(print);
-}
-
-Utils.exec(`mkdir -p ${GLib.get_user_state_dir()}/ags/user/ai`);
-const KEY_FILE_LOCATION = `${GLib.get_user_state_dir()}/ags/user/ai/google_key.txt`;
-const APIDOM_FILE_LOCATION = `${GLib.get_user_state_dir()}/ags/user/ai/google_api_dom.txt`;
-function replaceapidom(URL) {
- if (fileExists(APIDOM_FILE_LOCATION)) {
- var contents = Utils.readFile(APIDOM_FILE_LOCATION).trim();
- var URL = URL.toString().replace("generativelanguage.googleapis.com", contents);
- }
- return URL;
-}
-const CHAT_MODELS = ["gemini-2.0-flash"]
-const ONE_CYCLE_COUNT = 3;
-
-class GeminiMessage extends Service {
- static {
- Service.register(this,
- {
- 'delta': ['string'],
- },
- {
- 'content': ['string'],
- 'thinking': ['boolean'],
- 'done': ['boolean'],
- });
- }
-
- _role = '';
- _parts = [{ text: '' }];
- _lastContentLength = 0;
- _thinking;
- _done = false;
- _rawData = '';
-
- constructor(role, content, thinking = true, done = false) {
- super();
- this._role = role;
- this._parts = [{ text: content }];
- this._thinking = thinking;
- this._done = done;
- }
-
- get rawData() { return this._rawData }
- set rawData(value) { this._rawData = value }
-
- get done() { return this._done }
- set done(isDone) { this._done = isDone; this.notify('done') }
-
- get role() { return this._role }
- set role(role) { this._role = role; this.emit('changed') }
-
- get content() {
- return this._parts.map(part => part.text).join();
- }
- set content(content) {
- this._parts = [{ text: content }];
- if (content.length - this._lastContentLength >= userOptions.ai.charsEachUpdate) {
- this.notify('content')
- this.emit('changed')
- this._lastContentLength = content.length;
- }
- }
-
- get parts() { return this._parts }
-
- get label() { return this._parserState.parsed + this._parserState.stack.join('') }
-
- get thinking() { return this._thinking }
- set thinking(value) {
- this._thinking = value;
- this.notify('thinking')
- this.emit('changed')
- }
-
- addDelta(delta) {
- if (this.thinking) {
- this.thinking = false;
- this.content = delta;
- }
- else {
- this.content += delta;
- }
- this.emit('delta', delta);
- }
-
- parseSection() {
- if (this._thinking) {
- this.thinking = false;
- this._parts[0].text = '';
- }
- const parsedData = JSON.parse(this._rawData);
- if (!parsedData.candidates)
- this._parts[0].text += `Blocked: ${parsedData.promptFeedback.blockReason}`;
- else {
- const delta = parsedData.candidates[0].content.parts[0].text;
- this._parts[0].text += delta;
- }
- // this.emit('delta', delta);
- this.notify('content');
- this._rawData = '';
- }
-}
-
-class GeminiService extends Service {
- static {
- Service.register(this, {
- 'initialized': [],
- 'clear': [],
- 'newMsg': ['int'],
- 'hasKey': ['boolean'],
- });
- }
-
- _assistantPrompt = userOptions.ai.enhancements;
- _cycleModels = true;
- _usingHistory = userOptions.ai.useHistory;
- _key = '';
- _requestCount = 0;
- _safe = userOptions.ai.safety;
- _temperature = userOptions.ai.defaultTemperature;
- _messages = [];
- _modelIndex = 0;
- _decoder = new TextDecoder();
-
- constructor() {
- super();
-
- if (fileExists(KEY_FILE_LOCATION)) this._key = Utils.readFile(KEY_FILE_LOCATION).trim();
- else this.emit('hasKey', false);
-
- // if (this._usingHistory) Utils.timeout(1000, () => this.loadHistory());
- if (this._usingHistory) this.loadHistory();
- else this._messages = this._assistantPrompt ? [...initMessages] : [];
-
- this.emit('initialized');
- }
-
- get modelName() { return CHAT_MODELS[this._modelIndex] }
-
- get keyPath() { return KEY_FILE_LOCATION }
- get key() { return this._key }
- set key(keyValue) {
- this._key = keyValue;
- Utils.writeFile(this._key, KEY_FILE_LOCATION)
- .then(this.emit('hasKey', true))
- .catch(print);
- }
-
- get cycleModels() { return this._cycleModels }
- set cycleModels(value) {
- this._cycleModels = value;
- if (!value) this._modelIndex = 0;
- else {
- this._modelIndex = (this._requestCount - (this._requestCount % ONE_CYCLE_COUNT)) % CHAT_MODELS.length;
- }
- }
-
- get useHistory() { return this._usingHistory; }
- set useHistory(value) {
- // if (value && !this._usingHistory) this.loadHistory();
- this._usingHistory = value;
- }
-
- get safe() { return this._safe }
- set safe(value) { this._safe = value; }
-
- get temperature() { return this._temperature }
- set temperature(value) { this._temperature = value; }
-
- get messages() { return this._messages }
- get lastMessage() { return this._messages[this._messages.length - 1] }
-
- saveHistory() {
- Utils.exec(`bash -c 'mkdir -p ${HISTORY_DIR} && touch ${HISTORY_PATH}'`);
- Utils.writeFile(JSON.stringify(this._messages.map(msg => {
- let m = { role: msg.role, parts: msg.parts }; return m;
- })), HISTORY_PATH);
- }
-
- loadHistory() {
- this._messages = [];
- this.appendHistory();
- this._usingHistory = true;
- }
-
- appendHistory() {
- if (fileExists(HISTORY_PATH)) {
- const readfile = Utils.readFile(HISTORY_PATH);
- JSON.parse(readfile).forEach(element => {
- // this._messages.push(element);
- this.addMessage(element.role, element.parts[0].text);
- });
- // console.log(this._messages)
- // this._messages = this._messages.concat(JSON.parse(readfile));
- // for (let index = 0; index < this._messages.length; index++) {
- // this.emit('newMsg', index);
- // }
- }
- else {
- this._messages = this._assistantPrompt ? [...initMessages] : []
- }
- }
-
- clear() {
- this._messages = this._assistantPrompt ? [...initMessages] : [];
- if (this._usingHistory) this.saveHistory();
- this.emit('clear');
- }
-
- get assistantPrompt() { return this._assistantPrompt; }
- set assistantPrompt(value) {
- this._assistantPrompt = value;
- if (value) this._messages = [...initMessages];
- else this._messages = [];
- }
-
- readResponse(stream, aiResponse) {
- stream.read_line_async(
- 0, null,
- (stream, res) => {
- try {
- const [bytes] = stream.read_line_finish(res);
- const line = this._decoder.decode(bytes);
- console.log(line);
- if (line == '[{') { // beginning of response
- aiResponse._rawData += '{';
- this.thinking = false;
- }
- else if (line == ',\u000d' || line == ']') { // end of stream pulse
- aiResponse.parseSection();
- }
- else // Normal content
- aiResponse._rawData += line;
-
- this.readResponse(stream, aiResponse);
- } catch {
- aiResponse.done = true;
- if (this._usingHistory) this.saveHistory();
- return;
- }
- });
- }
-
- addMessage(role, message) {
- this._messages.push(new GeminiMessage(role, message, false));
- this.emit('newMsg', this._messages.length - 1);
- }
-
- send(msg) {
- this._messages.push(new GeminiMessage('user', msg, false));
- this.emit('newMsg', this._messages.length - 1);
- const aiResponse = new GeminiMessage('model', '', true, false)
-
- const body =
- {
- "contents": this._messages.map(msg => { let m = { role: msg.role, parts: msg.parts }; return m; }),
- "safetySettings": this._safe ? [] : [
- // { category: "HARM_CATEGORY_DEROGATORY", threshold: "BLOCK_NONE", },
- { category: "HARM_CATEGORY_HARASSMENT", threshold: "BLOCK_NONE", },
- { category: "HARM_CATEGORY_HATE_SPEECH", threshold: "BLOCK_NONE", },
- { category: "HARM_CATEGORY_SEXUALLY_EXPLICIT", threshold: "BLOCK_NONE", },
- // { category: "HARM_CATEGORY_UNSPECIFIED", threshold: "BLOCK_NONE", },
- ],
- "generationConfig": {
- "temperature": this._temperature,
- },
- "tools": [
- {
- "google_search": {}
- }
- ]
- };
- const proxyResolver = new Gio.SimpleProxyResolver({ 'default-proxy': userOptions.ai.proxyUrl });
- const session = new Soup.Session({ 'proxy-resolver': proxyResolver });
- const message = new Soup.Message({
- method: 'POST',
- uri: GLib.Uri.parse(replaceapidom(`https://generativelanguage.googleapis.com/v1beta/models/${this.modelName}:streamGenerateContent?key=${this._key}`), GLib.UriFlags.NONE),
- });
- message.request_headers.append('Content-Type', `application/json`);
- message.set_request_body_from_bytes('application/json', new GLib.Bytes(JSON.stringify(body)));
-
- session.send_async(message, GLib.DEFAULT_PRIORITY, null, (_, result) => {
- const stream = session.send_finish(result);
- this.readResponse(new Gio.DataInputStream({
- close_base_stream: true,
- base_stream: stream
- }), aiResponse);
- });
- this._messages.push(aiResponse);
- this.emit('newMsg', this._messages.length - 1);
-
- if (this._cycleModels) {
- this._requestCount++;
- if (this._cycleModels)
- this._modelIndex = (this._requestCount - (this._requestCount % ONE_CYCLE_COUNT)) % CHAT_MODELS.length;
- }
- }
-}
-
-export default new GeminiService();
diff --git a/.config/ags/services/gpt.js b/.config/ags/services/gpt.js
deleted file mode 100644
index 9279af0b1..000000000
--- a/.config/ags/services/gpt.js
+++ /dev/null
@@ -1,337 +0,0 @@
-import Service from 'resource:///com/github/Aylur/ags/service.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-
-import Gio from 'gi://Gio';
-import GLib from 'gi://GLib';
-import Soup from 'gi://Soup?version=3.0';
-import { fileExists } from '../modules/.miscutils/files.js';
-
-function guessModelLogo(model) {
- if (model.includes("llama")) return "ollama-symbolic";
- if (model.includes("gemma")) return "google-gemini-symbolic";
- if (model.includes("deepseek")) return "deepseek-symbolic";
- if (/^phi\d*:/i.test(model)) return "microsoft-symbolic";
- return "ollama-symbolic";
-}
-
-function guessModelName(model) {
- const replaced = model.replace(/-/g, ' ').replace(/:/g, ' ');
- const words = replaced.split(' ');
- words[words.length - 1] = words[words.length - 1].replace(/(\d+)b$/, (_, num) => `${num}B`)
- words[words.length - 1] = `[${words[words.length - 1]}]`; // Surround the last word with square brackets
- const result = words.join(' ');
- return result.charAt(0).toUpperCase() + result.slice(1); // Capitalize the first letter
-}
-
-const PROVIDERS = Object.assign({
- "ollama_llama_3_2": {
- "name": "Ollama - Llama 3.2",
- "logo_name": "ollama-symbolic",
- "description": getString('Ollama - Llama-3.2'),
- "base_url": 'http://localhost:11434/v1/chat/completions',
- "key_get_url": "",
- "requires_key": false,
- "key_file": "ollama_key.txt",
- "model": "llama3.2",
- },
- "openrouter": {
- "name": "OpenRouter (Llama-3-70B)",
- "logo_name": "openrouter-symbolic",
- "description": getString('A unified interface for LLMs'),
- "base_url": "https://openrouter.ai/api/v1/chat/completions",
- "key_get_url": "https://openrouter.ai/keys",
- "requires_key": true,
- "key_file": "openrouter_key.txt",
- "model": "meta-llama/llama-3-70b-instruct",
- },
-}, userOptions.ai.extraGptModels)
-
-const installedOllamaModels = JSON.parse(
- Utils.exec(`${App.configDir}/scripts/ai/show-installed-ollama-models.sh`))
- || [];
-installedOllamaModels.forEach(model => {
- const providerKey = `ollama_${model}`; // Generate a unique key for each model
- PROVIDERS[providerKey] = {
- name: `Ollama - ${guessModelName(model)}`,
- logo_name: guessModelLogo(model),
- description: `Ollama model: ${model}`,
- base_url: 'http://localhost:11434/v1/chat/completions',
- key_get_url: "",
- requires_key: false,
- key_file: "ollama_key.txt",
- model: `${model}`
- };
-});
-
-// Custom prompt
-const initMessages =
- [
- { role: "user", content: getString("You are an assistant on a sidebar of a Wayland Linux desktop. Please always use a casual tone when answering your questions, unless requested otherwise or making writing suggestions. These are the steps you should take to respond to the user's queries:\n1. If it's a writing- or grammar-related question or a sentence in quotation marks, Please point out errors and correct when necessary using underlines, and make the writing more natural where appropriate without making too major changes. If you're given a sentence in quotes but is grammatically correct, explain briefly concepts that are uncommon.\n2. If it's a question about system tasks, give a bash command in a code block with brief explanation.\n3. Otherwise, when asked to summarize information or explaining concepts, you are should use bullet points and headings. For mathematics expressions, you *have to* use LaTeX within a code block with the language set as \"latex\". \nNote: Use casual language, be short, while ensuring the factual correctness of your response. If you are unsure or don't have enough information to provide a confident answer, simply say \"I don't know\" or \"I'm not sure.\". \nThanks!") },
- { role: "assistant", content: "- Got it!", },
- { role: "user", content: "\"He rushed to where the event was supposed to be hold, he didn't know it got canceled\"", },
- { role: "assistant", content: "## Grammar correction\nErrors:\n\"He rushed to where the event was supposed to be __hold____,__ he didn't know it got canceled\"\nCorrection + minor improvements:\n\"He rushed to the place where the event was supposed to be __held____, but__ he didn't know that it got canceled\"", },
- { role: "user", content: "raise volume by 5%", },
- { role: "assistant", content: "## Volume +5\n```bash\nwpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+\n```\nThis command uses the `wpctl` utility to adjust the volume of the default sink.", },
- { role: "user", content: "main advantages of the nixos operating system", },
- { role: "assistant", content: "## NixOS advantages\n- **Reproducible**: A config working on one device will also work on another\n- **Declarative**: One config language to rule them all. Effortlessly share them with others.\n- **Reliable**: Per-program software versioning. Mitigates the impact of software breakage", },
- { role: "user", content: "whats skeumorphism", },
- { role: "assistant", content: "## Skeuomorphism\n- A design philosophy- From early days of interface designing- Tries to imitate real-life objects- It's in fact still used by Apple in their icons until today.", },
- ];
-
-Utils.exec(`mkdir -p ${GLib.get_user_state_dir()}/ags/user/ai`);
-
-class GPTMessage extends Service {
- static {
- Service.register(this,
- {
- 'delta': ['string'],
- },
- {
- 'content': ['string'],
- 'thinking': ['boolean'],
- 'done': ['boolean'],
- });
- }
-
- _role = '';
- _content = '';
- _hasReasoningContent = false;
- _parsedReasoningContent = false;
- _lastContentLength = 0;
- _thinking;
- _done = false;
-
- constructor(role, content, thinking = true, done = false) {
- super();
- this._role = role;
- this._hasReasoningContent = false;
- this._parsedReasoningContent = false;
- this._content = content;
- this._thinking = thinking;
- this._done = done;
- }
-
- get done() { return this._done }
- set done(isDone) { this._done = isDone; this.notify('done') }
-
- get role() { return this._role }
- set role(role) { this._role = role; this.emit('changed') }
-
- get hasReasoningContent() { return this._hasReasoningContent }
- set hasReasoningContent(value) {
- this._hasReasoningContent = value;
- this.emit('changed')
- }
-
- get parsedReasoningContent() { return this._parsedReasoningContent }
- set parsedReasoningContent(value) {
- this._parsedReasoningContent = value;
- this.emit('changed')
- }
-
- get content() { return this._content }
- set content(content) {
- this._content = content;
- if (this._content.length - this._lastContentLength >= userOptions.ai.charsEachUpdate) {
- this.notify('content')
- this.emit('changed')
- this._lastContentLength = this._content.length;
- }
- }
-
- get label() { return this._parserState.parsed + this._parserState.stack.join('') }
-
- get thinking() { return this._thinking }
- set thinking(value) {
- this._thinking = value;
- this.notify('thinking')
- this.emit('changed')
- }
-
- addDelta(delta) {
- if (delta == null) return;
- if (this.thinking) {
- this.thinking = false;
- this.content = delta;
- }
- else {
- this.content += delta;
- }
- this.emit('delta', delta);
- }
-}
-
-class GPTService extends Service {
- static {
- Service.register(this, {
- 'initialized': [],
- 'clear': [],
- 'newMsg': ['int'],
- 'hasKey': ['boolean'],
- 'providerChanged': [],
- });
- }
-
- _assistantPrompt = true;
- _currentProvider = PROVIDERS[userOptions.ai.defaultGPTProvider] ? userOptions.ai.defaultGPTProvider : Object.keys(PROVIDERS)[0];
- _requestCount = 0;
- _temperature = userOptions.ai.defaultTemperature;
- _messages = [];
- _key = '';
- _key_file_location = `${GLib.get_user_state_dir()}/ags/user/ai/${PROVIDERS[this._currentProvider]['key_file']}`;
- _url = GLib.Uri.parse(PROVIDERS[this._currentProvider]['base_url'], GLib.UriFlags.NONE);
-
- _decoder = new TextDecoder();
-
- _initChecks() {
- this._key_file_location = `${GLib.get_user_state_dir()}/ags/user/ai/${PROVIDERS[this._currentProvider]['key_file']}`;
- if (fileExists(this._key_file_location)) this._key = Utils.readFile(this._key_file_location).trim();
- else this.emit('hasKey', false);
- this._url = GLib.Uri.parse(PROVIDERS[this._currentProvider]['base_url'], GLib.UriFlags.NONE);
- }
-
- constructor() {
- super();
- this._initChecks();
-
- if (this._assistantPrompt) this._messages = [...initMessages];
- else this._messages = [];
-
- this.emit('initialized');
- }
-
- get modelName() { return PROVIDERS[this._currentProvider]['model'] }
- get getKeyUrl() { return PROVIDERS[this._currentProvider]['key_get_url'] }
- get providerID() { return this._currentProvider }
- set providerID(value) {
- this._currentProvider = value;
- this.emit('providerChanged');
- this._initChecks();
- }
- get providers() { return PROVIDERS }
-
- get keyPath() { return this._key_file_location }
- get key() { return this._key }
- set key(keyValue) {
- this._key = keyValue;
- Utils.writeFile(this._key, this._key_file_location)
- .then(this.emit('hasKey', true))
- .catch(print);
- }
-
- get temperature() { return this._temperature }
- set temperature(value) { this._temperature = value; }
-
- get messages() { return this._messages }
- get lastMessage() { return this._messages[this._messages.length - 1] }
-
- clear() {
- if (this._assistantPrompt)
- this._messages = [...initMessages];
- else
- this._messages = [];
- this.emit('clear');
- }
-
- get assistantPrompt() { return this._assistantPrompt; }
- set assistantPrompt(value) {
- this._assistantPrompt = value;
- if (value) this._messages = [...initMessages];
- else this._messages = [];
- }
-
- readResponse(stream, aiResponse) {
- aiResponse.thinking = false;
- stream.read_line_async(
- 0, null,
- (stream, res) => {
- if (!stream) return;
- const [bytes] = stream.read_line_finish(res);
- const line = this._decoder.decode(bytes);
- if (line && line != '') {
-
- // Ignore SSE comments (lines starting with ":")
- if (line.startsWith(':')) {
- this.readResponse(stream, aiResponse);
- return;
- }
-
- let data = line.substr(6);
- if (data == '[DONE]') return;
- try {
- const result = JSON.parse(data);
- if (result.choices[0].finish_reason === 'stop') {
- // If the stop payload has content, add it to the response
- if (result.choices[0].delta.content) {
- aiResponse.addDelta(result.choices[0].delta.content);
- }
- aiResponse.done = true;
- return;
- }
-
- // aiResponse.addDelta(result.choices[0].delta.content);
- if (!result.choices[0].delta.content && result.choices[0].delta.reasoning_content) {
- if (!aiResponse.hasReasoningContent) {
- aiResponse.hasReasoningContent = true;
- aiResponse.addDelta(`\n${result.choices[0].delta.reasoning_content}`);
- }
- else {
- aiResponse.addDelta(`${result.choices[0].delta.reasoning_content}`);
- }
- }
- else {
- if (aiResponse.hasReasoningContent) {
- aiResponse.parsedReasoningContent = true;
- aiResponse.addDelta(`\n\n`);
- }
- aiResponse.addDelta(result.choices[0].delta.content);
- }
- }
- catch {
- aiResponse.addDelta(line + '\n');
- }
- }
- this.readResponse(stream, aiResponse);
- });
- }
-
- addMessage(role, message) {
- this._messages.push(new GPTMessage(role, message));
- this.emit('newMsg', this._messages.length - 1);
- }
-
- send(msg) {
- this._messages.push(new GPTMessage('user', msg, false, true));
- this.emit('newMsg', this._messages.length - 1);
- const aiResponse = new GPTMessage('assistant', '', true, false)
-
- const body = {
- "model": PROVIDERS[this._currentProvider]['model'],
- "messages": this._messages.map(msg => { let m = { role: msg.role, content: msg.content }; return m; }),
- "temperature": this._temperature,
- "stream": true,
- "keep_alive": userOptions.ai.keepAlive,
- };
- // console.log(body);
- const proxyResolver = new Gio.SimpleProxyResolver({ 'default-proxy': userOptions.ai.proxyUrl });
- const session = new Soup.Session({ 'proxy-resolver': proxyResolver });
- const message = new Soup.Message({
- method: 'POST',
- uri: this._url,
- });
- message.request_headers.append('Authorization', `Bearer ${this._key}`);
- message.set_request_body_from_bytes('application/json', new GLib.Bytes(JSON.stringify(body)));
-
- session.send_async(message, GLib.DEFAULT_PRIORITY, null, (_, result) => {
- const stream = session.send_finish(result);
- this.readResponse(new Gio.DataInputStream({
- close_base_stream: true,
- base_stream: stream
- }), aiResponse);
- });
- this._messages.push(aiResponse);
- this.emit('newMsg', this._messages.length - 1);
- }
-}
-
-export default new GPTService();
\ No newline at end of file
diff --git a/.config/ags/services/indicator.js b/.config/ags/services/indicator.js
deleted file mode 100644
index dfe141ee1..000000000
--- a/.config/ags/services/indicator.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import Service from 'resource:///com/github/Aylur/ags/service.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-
-class IndicatorService extends Service {
- static {
- Service.register(
- this,
- { 'popup': ['double'], },
- );
- }
-
- _delay = 1500;
- _count = 0;
-
- popup(value) {
- this.emit('popup', value);
- this._count++;
- Utils.timeout(this._delay, () => {
- this._count--;
-
- if (this._count === 0)
- this.emit('popup', -1);
- });
- }
-
- connectWidget(widget, callback) {
- connect(this, widget, callback, 'popup');
- }
-}
-
-// the singleton instance
-const service = new IndicatorService();
-
-// make it global for easy use with cli
-globalThis['indicator'] = service;
-
-// export to use in other modules
-export default service;
\ No newline at end of file
diff --git a/.config/ags/services/messages.js b/.config/ags/services/messages.js
deleted file mode 100644
index b2d3b05f3..000000000
--- a/.config/ags/services/messages.js
+++ /dev/null
@@ -1,62 +0,0 @@
-const { Notify, GLib, Gio } = imports.gi;
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-import Battery from 'resource:///com/github/Aylur/ags/service/battery.js';
-
-export function fileExists(filePath) {
- let file = Gio.File.new_for_path(filePath);
- return file.query_exists(null);
-}
-
-const FIRST_RUN_FILE = "firstrun.txt";
-const FIRST_RUN_PATH = `${GLib.get_user_state_dir()}/ags/user/${FIRST_RUN_FILE}`;
-const FIRST_RUN_FILE_CONTENT = "Just a file to confirm that you have been greeted ;)";
-const APP_NAME = "illogical-impulse";
-const FIRST_RUN_NOTIF_TITLE = "Welcome!";
-const FIRST_RUN_NOTIF_BODY = `First run? For a list of keybinds, hit Super + /.`;
-
-var batteryWarned = false;
-async function batteryMessage() {
- const perc = Battery.percent;
- const charging = Battery.charging;
- if (charging) {
- batteryWarned = false;
- return;
- }
- for (let i = userOptions.battery.warnLevels.length - 1; i >= 0; i--) {
- if (perc <= userOptions.battery.warnLevels[i] && !charging && !batteryWarned) {
- batteryWarned = true;
- Utils.execAsync(['bash', '-c',
- `notify-send "${userOptions.battery.warnTitles[i]}" "${userOptions.battery.warnMessages[i]}" -u critical -a '${APP_NAME}' -t 69420 &`
- ]).catch(print);
- break;
- }
- }
- if (perc <= userOptions.battery.suspendThreshold) {
- Utils.execAsync(['bash', '-c',
- `notify-send "Suspending system" "Critical battery level (${perc}% remaining)" -u critical -a '${APP_NAME}' -t 69420 &`
- ]).catch(print);
- Utils.execAsync('systemctl suspend').catch(print);
- }
-}
-
-export async function startBatteryWarningService() {
- Utils.timeout(1, () => {
- Battery.connect('changed', () => batteryMessage().catch(print));
- })
-}
-
-export async function firstRunWelcome() {
- GLib.mkdir_with_parents(`${GLib.get_user_state_dir()}/ags/user`, 755);
- if (!fileExists(FIRST_RUN_PATH)) {
- Utils.execAsync([`bash`, `-c`, `${App.configDir}/scripts/color_generation/switchwall.sh '${App.configDir}/assets/images/default_wallpaper.png'`]).catch(print);
- Utils.writeFile(FIRST_RUN_FILE_CONTENT, FIRST_RUN_PATH)
- .then(() => {
- // Note that we add a little delay to make sure the cool circular progress works
- Utils.execAsync(['hyprctl', 'keyword', 'bind', 'Super,Slash,exec,for ((i=0; i<$(hyprctl monitors -j | jq length); i++)); do ags -t "cheatsheet""$i"; done']).catch(print);
- Utils.execAsync(['bash', '-c',
- `sleep 0.5; notify-send "Millis since epoch" "$(date +%s%N | cut -b1-13)"; sleep 0.5; notify-send '${FIRST_RUN_NOTIF_TITLE}' '${FIRST_RUN_NOTIF_BODY}' -a '${APP_NAME}' &`
- ]).catch(print)
- })
- .catch(print);
- }
-}
diff --git a/.config/ags/services/sway.js b/.config/ags/services/sway.js
deleted file mode 100644
index 388372e9c..000000000
--- a/.config/ags/services/sway.js
+++ /dev/null
@@ -1,400 +0,0 @@
-import GLib from 'gi://GLib';
-import Gio from 'gi://Gio';
-import Service from "resource:///com/github/Aylur/ags/service.js";
-
-const SIS = GLib.getenv('SWAYSOCK');
-
-export const PAYLOAD_TYPE = {
- MESSAGE_RUN_COMMAND: 0,
- MESSAGE_GET_WORKSPACES: 1,
- MESSAGE_SUBSCRIBE: 2,
- MESSAGE_GET_OUTPUTS: 3,
- MESSAGE_GET_TREE: 4,
- MESSAGE_GET_MARKS: 5,
- MESSAGE_GET_BAR_CONFIG: 6,
- MESSAGE_GET_VERSION: 7,
- MESSAGE_GET_BINDING_NODES: 8,
- MESSAGE_GET_CONFIG: 9,
- MESSAGE_SEND_TICK: 10,
- MESSAGE_SYNC: 11,
- MESSAGE_GET_BINDING_STATE: 12,
- MESSAGE_GET_INPUTS: 100,
- MESSAGE_GET_SEATS: 101,
- EVENT_WORKSPACE: 0x80000000,
- EVENT_MODE: 0x80000002,
- EVENT_WINDOW: 0x80000003,
- EVENT_BARCONFIG_UPDATE: 0x80000004,
- EVENT_BINDING: 0x80000005,
- EVENT_SHUTDOWN: 0x80000006,
- EVENT_TICK: 0x80000007,
- EVENT_BAR_STATE_UPDATE: 0x80000014,
- EVENT_INPUT: 0x80000015,
-}
-
-const Client_Event = {
- change: undefined,
- container: undefined,
-}
-
-const Workspace_Event = {
- change: undefined,
- current: undefined,
- old: undefined,
-}
-
-const Geometry = {
- x: undefined,
- y: undefined,
- width: undefined,
- height: undefined,
-}
-
-//NOTE: not all properties are listed here
-export const Node = {
- id: undefined,
- name: undefined,
- type: undefined,
- border: undefined,
- current_border_width: undefined,
- layout: undefined,
- orientation: undefined,
- percent: undefined,
- rect: undefined,
- window_rect: undefined,
- deco_rect: undefined,
- geometry: undefined,
- urgent: undefined,
- sticky: undefined,
- marks: undefined,
- focused: undefined,
- active: undefined,
- focus: undefined,
- nodes: undefined,
- floating_nodes: undefined,
- representation: undefined,
- fullscreen_mode: undefined,
- app_id: undefined,
- pid: undefined,
- visible: undefined,
- shell: undefined,
- output: undefined,
- inhibit_idle: undefined,
- idle_inhibitors: {
- application: undefined,
- user: undefined,
- },
- window: undefined,
- window_properties: {
- title: undefined,
- class: undefined,
- instance: undefined,
- window_role: undefined,
- window_type: undefined,
- transient_for: undefined,
- }
-}
-
-export class SwayActiveClient extends Service {
- static {
- Service.register(this, {}, {
- 'id': ['int'],
- 'name': ['string'],
- 'class': ['string'],
- });
- }
-
- _id = 0;
- _name = '';
- _class = '';
-
- get id() { return this._id; }
- get name() { return this._name; }
- get class() { return this._class; }
-
- updateProperty(prop, value) {
- if (!['id', 'name', 'class'].includes(prop)) return;
- super.updateProperty(prop, value);
- this.emit('changed');
- }
-}
-
-export class SwayActiveID extends Service {
- static {
- Service.register(this, {}, {
- 'id': ['int'],
- 'name': ['string'],
- });
- }
-
- _id = 0;
- _name = '';
-
- get id() { return this._id; }
- get name() { return this._name; }
-
- update(id, name) {
- super.updateProperty('id', id);
- super.updateProperty('name', name);
- this.emit('changed');
- }
-}
-
-export class SwayActives extends Service {
- static {
- Service.register(this, {}, {
- 'client': ['jsobject'],
- 'monitor': ['jsobject'],
- 'workspace': ['jsobject'],
- });
- }
-
- _client = new SwayActiveClient;
- _monitor = new SwayActiveID;
- _workspace = new SwayActiveID;
-
- constructor() {
- super();
-
- (['client', 'workspace', 'monitor']).forEach(obj => {
- this[`_${obj}`].connect('changed', () => {
- this.notify(obj);
- this.emit('changed');
- });
- });
- }
-
- get client() { return this._client; }
- get monitor() { return this._monitor; }
- get workspace() { return this._workspace; }
-}
-
-export class Sway extends Service {
- static {
- Service.register(this, {}, {
- 'active': ['jsobject'],
- 'monitors': ['jsobject'],
- 'workspaces': ['jsobject'],
- 'clients': ['jsobject'],
- });
- }
-
- _decoder = new TextDecoder();
- _encoder = new TextEncoder();
- _socket;
-
- _active;
- _monitors;
- _workspaces;
- _clients;
-
- get active() { return this._active; }
- get monitors() { return Array.from(this._monitors.values()); }
- get workspaces() { return Array.from(this._workspaces.values()); }
- get clients() { return Array.from(this._clients.values()); }
-
- getMonitor(id) { return this._monitors.get(id); }
- getWorkspace(name) { return this._workspaces.get(name); }
- getClient(id) { return this._clients.get(id); }
-
- msg(payload) { this._send(PAYLOAD_TYPE.MESSAGE_RUN_COMMAND, payload); }
-
- constructor() {
- if (!SIS)
- console.error('Sway is not running');
- super();
-
- this._active = new SwayActives();
- this._monitors = new Map();
- this._workspaces = new Map();
- this._clients = new Map();
-
- this._socket = new Gio.SocketClient().connect(new Gio.UnixSocketAddress({
- path: `${SIS}`,
- }), null);
-
- this._watchSocket(this._socket.get_input_stream());
- this._send(PAYLOAD_TYPE.MESSAGE_GET_TREE, '');
- this._send(PAYLOAD_TYPE.MESSAGE_SUBSCRIBE, JSON.stringify(['window', 'workspace']));
-
- this._active.connect('changed', () => this.emit('changed'));
- ['monitor', 'workspace', 'client'].forEach(active =>
- this._active.connect(`notify::${active}`, () => this.notify('active')));
- }
-
- _send(payloadType, payload) {
- const pb = this._encoder.encode(payload);
- const type = new Uint32Array([payloadType]);
- const pl = new Uint32Array([pb.length]);
- const magic_string = this._encoder.encode('i3-ipc');
- const data = new Uint8Array([
- ...magic_string,
- ...(new Uint8Array(pl.buffer)),
- ...(new Uint8Array(type.buffer)),
- ...pb]);
- this._socket.get_output_stream().write(data, null);
- }
-
- _watchSocket(stream) {
- stream.read_bytes_async(14, GLib.PRIORITY_DEFAULT, null, (_, resultHeader) => {
- const data = stream.read_bytes_finish(resultHeader).get_data();
- if (!data)
- return;
- const payloadLength = new Uint32Array(data.slice(6, 10).buffer)[0];
- const payloadType = new Uint32Array(data.slice(10, 14).buffer)[0];
- stream.read_bytes_async(
- payloadLength,
- GLib.PRIORITY_DEFAULT,
- null,
- (_, resultPayload) => {
- const data = stream.read_bytes_finish(resultPayload).get_data();
- if (!data)
- return;
- this._onEvent(payloadType, JSON.parse(this._decoder.decode(data)));
- this._watchSocket(stream);
- });
- });
- }
-
- async _onEvent(event_type, event) {
- if (!event)
- return;
- try {
- switch (event_type) {
- case PAYLOAD_TYPE.EVENT_WORKSPACE:
- this._handleWorkspaceEvent(event);
- break;
- case PAYLOAD_TYPE.EVENT_WINDOW:
- this._handleWindowEvent(event);
- break;
- case PAYLOAD_TYPE.MESSAGE_GET_TREE:
- this._handleTreeMessage(event);
- break;
- default:
- break;
- }
- } catch (error) {
- logError(error);
- }
- this.emit('changed');
- }
-
- _handleWorkspaceEvent(workspaceEvent) {
- const workspace = workspaceEvent.current;
- switch (workspaceEvent.change) {
- case 'init':
- this._workspaces.set(workspace.name, workspace);
- break;
- case 'empty':
- this._workspaces.delete(workspace.name);
- break;
- case 'focus':
- this._active.workspace.update(workspace.id, workspace.name);
- this._active.monitor.update(1, workspace.output);
-
- this._workspaces.set(workspace.name, workspace);
- this._workspaces.set(workspaceEvent.old.name, workspaceEvent.old);
- break;
- case 'rename':
- if (this._active.workspace.id === workspace.id)
- this._active.workspace.updateProperty('name', workspace.name);
- this._workspaces.set(workspace.name, workspace);
- break;
- case 'reload':
- break;
- case 'move':
- case 'urgent':
- default:
- this._workspaces.set(workspace.name, workspace);
- }
- this.notify('workspaces');
- }
-
- _handleWindowEvent(clientEvent) {
- const client = clientEvent.container;
- const id = client.id;
- switch (clientEvent.change) {
- case 'new':
- case 'close':
- case 'floating':
- case 'move':
- // Refresh tree since client events don't contain the relevant information
- // to be able to modify `workspace.nodes` or `workspace.floating_nodes`.
- // There has to be a better way than this though :/
- this._send(PAYLOAD_TYPE.MESSAGE_GET_TREE, '');
- break;
- case 'focus':
- if (this._active.client.id === id)
- return;
- // eslint-disable-next-line no-case-declarations
- const current_active = this._clients.get(this._active.client.id);
- if (current_active)
- current_active.focused = false;
- this._active.client.updateProperty('id', id);
- this._active.client.updateProperty('name', client.name);
- this._active.client.updateProperty('class', client.shell === 'xwayland'
- ? client.window_properties?.class || ''
- : client.app_id,
- );
- break;
- case 'title':
- if (client.focused)
- this._active.client.updateProperty('name', client.name);
- this._clients.set(id, client);
- this.notify('clients');
- break;
- case 'fullscreen_mode':
- case 'urgent':
- case 'mark':
- default:
- this._clients.set(id, client);
- this.notify('clients');
- }
- }
-
- _handleTreeMessage(node) {
- switch (node.type) {
- case 'root':
- this._workspaces.clear();
- this._clients.clear();
- this._monitors.clear();
- node.nodes.map(n => this._handleTreeMessage(n));
- break;
- case 'output':
- this._monitors.set(node.id, node);
- if (node.active)
- this._active.monitor.update(node.id, node.name);
- node.nodes.map(n => this._handleTreeMessage(n));
- this.notify('monitors');
- break;
- case 'workspace':
- this._workspaces.set(node.name, node);
- // I think I'm missing something. There has to be a better way.
- // eslint-disable-next-line no-case-declarations
- const hasFocusedChild =
- (n) => n.nodes.some(c => c.focused || hasFocusedChild(c));
- if (node.focused || hasFocusedChild(node))
- this._active.workspace.update(node.id, node.name);
-
- node.nodes.map(n => this._handleTreeMessage(n));
- this.notify('workspaces');
- break;
- case 'con':
- case 'floating_con':
- this._clients.set(node.id, node);
- if (node.focused) {
- this._active.client.updateProperty('id', node.id);
- this._active.client.updateProperty('name', node.name);
- this._active.client.updateProperty('class', node.shell === 'xwayland'
- ? node.window_properties?.class || ''
- : node.app_id,
- );
- }
- node.nodes.map(n => this._handleTreeMessage(n));
- this.notify('clients');
- break;
- }
- }
-}
-
-export const sway = new Sway;
-export default sway;
\ No newline at end of file
diff --git a/.config/ags/services/todo.js b/.config/ags/services/todo.js
deleted file mode 100644
index d5384f3be..000000000
--- a/.config/ags/services/todo.js
+++ /dev/null
@@ -1,83 +0,0 @@
-const { Gio, GLib } = imports.gi;
-import Service from 'resource:///com/github/Aylur/ags/service.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { exec, execAsync } = Utils;
-
-class TodoService extends Service {
- static {
- Service.register(
- this,
- { 'updated': [], },
- );
- }
-
- _todoPath = '';
- _todoJson = [];
-
- refresh(value) {
- this.emit('updated', value);
- }
-
- connectWidget(widget, callback) {
- this.connect(widget, callback, 'updated');
- }
-
- get todo_json() {
- return this._todoJson;
- }
-
- _save() {
- Utils.writeFile(JSON.stringify(this._todoJson), this._todoPath)
- .catch(print);
- }
-
- add(content) {
- this._todoJson.push({ content, done: false });
- this._save();
- this.emit('updated');
- }
-
- check(index) {
- this._todoJson[index].done = true;
- this._save();
- this.emit('updated');
- }
-
- uncheck(index) {
- this._todoJson[index].done = false;
- this._save();
- this.emit('updated');
- }
-
- remove(index) {
- this._todoJson.splice(index, 1);
- Utils.writeFile(JSON.stringify(this._todoJson), this._todoPath)
- .catch(print);
- this.emit('updated');
- }
-
- constructor() {
- super();
- this._todoPath = `${GLib.get_user_state_dir()}/ags/user/todo.json`;
- try {
- const fileContents = Utils.readFile(this._todoPath);
- this._todoJson = JSON.parse(fileContents);
- }
- catch {
- Utils.exec(`bash -c 'mkdir -p ${GLib.get_user_cache_dir()}/ags/user'`);
- Utils.exec(`touch ${this._todoPath}`);
- Utils.writeFile("[]", this._todoPath).then(() => {
- this._todoJson = JSON.parse(Utils.readFile(this._todoPath))
- }).catch(print);
- }
- }
-}
-
-// the singleton instance
-const service = new TodoService();
-
-// make it global for easy use with cli
-globalThis.todo = service;
-
-// export to use in other modules
-export default service;
\ No newline at end of file
diff --git a/.config/ags/services/waifus.js b/.config/ags/services/waifus.js
deleted file mode 100644
index 8512ed59f..000000000
--- a/.config/ags/services/waifus.js
+++ /dev/null
@@ -1,150 +0,0 @@
-import Service from 'resource:///com/github/Aylur/ags/service.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-
-// Note: this service is made mainly for waifu.im. Others might work but not as properly
-const APISERVICES = {
- 'im': {
- 'endpoint': 'https://api.waifu.im/search',
- 'headers': { 'Accept-Version': 'v5' },
- },
- 'nekos': {
- 'endpoint': 'https://nekos.life/api/neko',
- 'headers': {},
- },
- 'pics': {
- 'endpoint': 'https://api.waifu.pics/sfw/',
- 'headers': {},
- },
-};
-
-function paramStringFromObj(params) {
- return Object.entries(params)
- .map(([key, value]) => {
- if (Array.isArray(value)) { // If it's an array, repeat
- if (value.length == 0) return '';
- let thisKey = `${encodeURIComponent(key)}=${encodeURIComponent(value[0])}`
- for (let i = 1; i < value.length; i++) {
- thisKey += `&${encodeURIComponent(key)}=${encodeURIComponent(value[i])}`;
- }
- return thisKey;
- }
- return `${key}=${value}`;
- })
- .join('&');
-}
-
-class WaifuService extends Service {
- _baseUrl = 'https://api.waifu.im/search';
- _mode = 'im'; // Allowed: im
- _responses = [];
- _queries = [];
- _nsfw = false;
- _minHeight = 600;
-
- static {
- Service.register(this, {
- 'initialized': [],
- 'clear': [],
- 'newResponse': ['int'],
- 'updateResponse': ['int'],
- });
- }
-
- constructor() {
- super();
- this.emit('initialized');
- }
-
- clear() {
- this._responses = [];
- this._queries = [];
- this.emit('clear');
- }
-
- get mode() { return this._mode }
- set mode(value) {
- this._mode = value;
- this._baseUrl = APISERVICES[this._mode].endpoint;
- }
- get nsfw() { return this._nsfw }
- set nsfw(value) { this._nsfw = value }
- get queries() { return this._queries }
- get responses() { return this._responses }
-
- async fetch(msg) {
- // Init
- const userArgs = msg.split(/\s+/);
-
- let taglist = [];
- this._nsfw = false;
- // Construct body/headers
- for (let i = 0; i < userArgs.length; i++) {
- const thisArg = userArgs[i].trim();
- if (thisArg.length == 0) continue;
- if (thisArg == '--im') this._mode = 'im';
- else if (thisArg == '--nekos') this._mode = 'nekos';
- else if (thisArg.includes('pics')) this._mode = 'pics';
- else if (thisArg.includes('segs') || thisArg.includes('sex') || thisArg.includes('lewd')) this._nsfw = true;
- else {
- taglist.push(thisArg);
- if (['ecchi', 'hentai', 'ero', 'ass', 'paizuri', 'oral', 'milf'].includes(thisArg)) this._nsfw = true;
- }
- }
- const newMessageId = this._queries.length;
- this._queries.push(taglist);
- this.emit('newResponse', newMessageId);
- const params = {
- 'included_tags': taglist,
- 'height': `>=${this._minHeight}`,
- 'nsfw': this._nsfw,
- };
- const paramString = paramStringFromObj(params);
- // Fetch
- // Note: body isn't included since passing directly to url is more reliable
- const options = {
- method: 'GET',
- headers: APISERVICES[this._mode].headers,
- };
- let status = 0;
- Utils.fetch(`${APISERVICES[this._mode].endpoint}?${paramString}`, options)
- .then(result => {
- status = result.status;
- return result.text();
- })
- .then((dataString) => { // Store interesting stuff and emit
- const parsedData = JSON.parse(dataString);
- if (!parsedData.images) this._responses.push({ // Failed
- status: status,
- signature: -1,
- url: '',
- extension: '',
- source: '',
- dominant_color: '#383A40',
- is_nsfw: false,
- width: 0,
- height: 0,
- tags: [],
- });
- else {
- const imageData = parsedData.images[0];
- this._responses.push({
- status: status,
- signature: imageData?.signature || -1,
- url: imageData?.url || undefined,
- extension: imageData.extension,
- source: imageData?.source,
- dominant_color: imageData?.dominant_color || '#9392A6',
- is_nsfw: imageData?.is_nsfw || false,
- width: imageData?.width || 0,
- height: imageData?.height || 0,
- tags: imageData?.tags.map(obj => obj["name"]) || [],
- });
- }
- this.emit('updateResponse', newMessageId);
- })
- .catch(print);
- }
-}
-
-export default new WaifuService();
-
diff --git a/.config/ags/services/wallpaper.js b/.config/ags/services/wallpaper.js
deleted file mode 100644
index 9fa2b83ff..000000000
--- a/.config/ags/services/wallpaper.js
+++ /dev/null
@@ -1,70 +0,0 @@
-const { Gdk, GLib } = imports.gi;
-import Service from 'resource:///com/github/Aylur/ags/service.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-
-const WALLPAPER_CONFIG_PATH = `${GLib.get_user_state_dir()}/ags/user/wallpaper.json`;
-
-class WallpaperService extends Service {
- static {
- Service.register(
- this,
- { 'updated': [], },
- );
- }
-
- _wallPath = '';
- _wallJson = [];
- _monitorCount = 1;
-
- _save() {
- Utils.writeFile(JSON.stringify(this._wallJson), this._wallPath)
- .catch(print);
- }
-
- add(path) {
- this._wallJson.push(path);
- this._save();
- this.emit('updated');
- }
-
- set(path, monitor = -1) {
- this._monitorCount = Gdk.Display.get_default()?.get_n_monitors() || 1;
- if (this._wallJson.length < this._monitorCount) this._wallJson[this._monitorCount - 1] = "";
- if (monitor == -1)
- this._wallJson.fill(path);
- else
- this._wallJson[monitor] = path;
-
- this._save();
- this.emit('updated');
- }
-
- get(monitor = 0) {
- return this._wallJson[monitor];
- }
-
- constructor() {
- super();
- // How many screens?
- this._monitorCount = Gdk.Display.get_default()?.get_n_monitors() || 1;
- // Read config
- this._wallPath = WALLPAPER_CONFIG_PATH;
- try {
- const fileContents = Utils.readFile(this._wallPath);
- this._wallJson = JSON.parse(fileContents);
- }
- catch {
- Utils.exec(`bash -c 'mkdir -p ${GLib.get_user_cache_dir()}/ags/user'`);
- Utils.exec(`touch ${this._wallPath}`);
- Utils.writeFile('[]', this._wallPath).then(() => {
- this._wallJson = JSON.parse(Utils.readFile(this._wallPath))
- }).catch(print);
- }
- }
-}
-
-// instance
-const service = new WallpaperService();
-// make it global for easy use with cli
-globalThis['wallpaper'] = service;
-export default service;
\ No newline at end of file
diff --git a/.config/ags/user_options.jsonc b/.config/ags/user_options.jsonc
deleted file mode 100644
index 4c44fe01c..000000000
--- a/.config/ags/user_options.jsonc
+++ /dev/null
@@ -1,19 +0,0 @@
-// Options in this file override the defaults in:
-// ~/.config/ags/modules/.configuration/default_options.jsonc
-//
-// vscode: ctrl+click this: file://./modules/.configuration/default_options.jsonc
-// vim: `:vsp` to split window, move cursor to the path, press `gf`.
-// `Ctrl-w` twice to switch between the files
-//
-// Limitations of this file:
-// * Only line comments (//) are allowed
-// * Comments are not allowed in or below the actual content
-// (will be nuked with updates from the UI)
-//
-//
-// Example: Put this to show 8 (instead of 10) workspaces on the bar
-// "workspaces": {"shown": 8 }
-//
-{
-
-}
diff --git a/.config/ags/variables.js b/.config/ags/variables.js
deleted file mode 100644
index 347d006d0..000000000
--- a/.config/ags/variables.js
+++ /dev/null
@@ -1,84 +0,0 @@
-const { Gdk, Gtk } = imports.gi;
-import App from 'resource:///com/github/Aylur/ags/app.js'
-import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
-import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js';
-import Variable from 'resource:///com/github/Aylur/ags/variable.js';
-import * as Utils from 'resource:///com/github/Aylur/ags/utils.js';
-const { exec, execAsync } = Utils;
-import { init as i18n_init, getString } from './i18n/i18n.js'
-//init i18n, Load language file
-i18n_init()
-Gtk.IconTheme.get_default().append_search_path(`${App.configDir}/assets/icons`);
-
-// Global vars for external control (through keybinds)
-export const showMusicControls = Variable(false, {})
-export const showColorScheme = Variable(false, {})
-globalThis['openMusicControls'] = showMusicControls;
-globalThis['openColorScheme'] = showColorScheme;
-globalThis['mpris'] = Mpris;
-globalThis['getString'] = getString
-// load monitor shell modes from userOptions
-const initialMonitorShellModes = () => {
- const numberOfMonitors = Gdk.Display.get_default()?.get_n_monitors() || 1;
- const monitorBarConfigs = [];
- for (let i = 0; i < numberOfMonitors; i++) {
- if (userOptions.bar.modes[i]) {
- monitorBarConfigs.push(userOptions.bar.modes[i])
- } else {
- monitorBarConfigs.push('normal')
- }
- }
- return monitorBarConfigs;
-
-}
-export const currentShellMode = Variable(initialMonitorShellModes(), {}) // normal, focus
-
-// Mode switching
-const updateMonitorShellMode = (monitorShellModes, monitor, mode) => {
- const newValue = [...monitorShellModes.value];
- newValue[monitor] = mode;
- monitorShellModes.value = newValue;
-}
-globalThis['currentMode'] = currentShellMode;
-globalThis['cycleMode'] = () => {
- const monitor = Hyprland.active.monitor.id || 0;
-
- if (currentShellMode.value[monitor] === 'normal') {
- updateMonitorShellMode(currentShellMode, monitor, 'focus')
- }
- else if (currentShellMode.value[monitor] === 'focus') {
- updateMonitorShellMode(currentShellMode, monitor, 'nothing')
- }
- else {
- updateMonitorShellMode(currentShellMode, monitor, 'normal')
- }
-}
-
-// Window controls
-const range = (length, start = 1) => Array.from({ length }, (_, i) => i + start);
-globalThis['toggleWindowOnAllMonitors'] = (name) => {
- range(Gdk.Display.get_default()?.get_n_monitors() || 1, 0).forEach(id => {
- App.toggleWindow(`${name}${id}`);
- });
-}
-globalThis['closeWindowOnAllMonitors'] = (name) => {
- range(Gdk.Display.get_default()?.get_n_monitors() || 1, 0).forEach(id => {
- App.closeWindow(`${name}${id}`);
- });
-}
-globalThis['openWindowOnAllMonitors'] = (name) => {
- range(Gdk.Display.get_default()?.get_n_monitors() || 1, 0).forEach(id => {
- App.openWindow(`${name}${id}`);
- });
-}
-
-globalThis['closeEverything'] = () => {
- const numMonitors = Gdk.Display.get_default()?.get_n_monitors() || 1;
- for (let i = 0; i < numMonitors; i++) {
- App.closeWindow(`cheatsheet${i}`);
- App.closeWindow(`session${i}`);
- }
- App.closeWindow('sideleft');
- App.closeWindow('sideright');
- App.closeWindow('overview');
-};