39 Commits

Author SHA1 Message Date
Stephen Horvath
43de4d979d Release 1.0 2026-03-21 16:46:39 +10:00
Stephen Horvath
d1ea86f694 Update screenshots 2026-03-21 15:01:00 +10:00
Stephen Horvath
aa8e05f676 Update deprecated GitHub Workflows 2026-03-21 14:40:15 +10:00
Stephen Horvath
f45cb3db36 Windows: Update PawnIO module, Gvsbuild, and ico 2026-03-21 14:22:34 +10:00
Stephen Horvath
a91556e3e6 Fix battery page crashing when there is no battery 2026-01-17 21:52:18 +10:00
Stephen Horvath
f8f043cf48 Future fix for broken temperature sensors 2026-01-17 21:51:59 +10:00
Stephen Horvath
8453f41914 Remove broken charge limit override 2026-01-12 22:05:36 +10:00
Stephen Horvath
a0ba66ab99 Fix ListBox desync when selecting About 2026-01-12 21:59:51 +10:00
Stephen Horvath
7c89b4197f Add Mirabelle to artists 2026-01-09 11:07:16 +10:00
Stephen Horvath
c9b659e22a Merge pull request #19 from oiimrosabel/main
Add application icons
2026-01-09 10:14:53 +10:00
Rosabel
3e7873de8f Add application icons
Adds application icon in scalable and symbolic formats.
2026-01-08 18:21:45 +01:00
Stephen Horvath
988aabea07 Merge pull request #16 from TheBlueOompaLoompa/main
Fix udev rule quotes
2025-12-26 12:53:15 +10:00
TheBlueOompaLoompa
804ae3fcb6 Fix udev rule quotes 2025-12-25 18:50:31 -06:00
Stephen Horvath
a97148f7a5 Release 0.7 2025-12-25 20:48:18 +10:00
Stephen Horvath
8b10c49ed4 Update Python on Windows CI 2025-12-25 20:15:14 +10:00
Stephen Horvath
f31054c18b Update Gvsbuild on CI 2025-12-25 20:10:22 +10:00
Stephen Horvath
2b50f0816f Implement fan set points 2025-12-25 19:35:33 +10:00
Stephen Horvath
1fc4b94237 Streamline udev rules 2025-11-06 13:58:51 +10:00
Stephen Horvath
90a994a685 Disable blue power button colour
Early Intel models report that their power button LED supports blue
colour, but in reality it just turns it off.
2025-10-20 15:07:37 +10:00
Stephen Horvath
7b123da001 Handle custom power LED brightness levels 2025-10-16 22:45:23 +10:00
Stephen Horvath
c8fd626446 Update about text to match README 2025-10-04 10:32:09 +10:00
Stephen Horvath
0f6fee40ae Add disclaimer to README 2025-10-04 10:29:23 +10:00
Stephen Horvath
4a788c2395 Merge pull request #11 from OrioleNix/patch-1
Change title from gtk3 to gtk4
2025-10-04 07:05:08 +10:00
OrioleNix
d2f34c9b5a Update main.py 2025-10-03 11:22:34 -04:00
Stephen Horvath
4958722edd Update README.md 2025-09-28 23:26:39 +10:00
Stephen Horvath
23b54ee397 Add FUNDING.yml 2025-09-28 23:24:51 +10:00
Stephen Horvath
73bb7abf6e Release 0.6 2025-09-28 13:35:13 +10:00
Stephen Horvath
9f0fabb91f Fix metainfo screenshots 2025-09-28 12:55:28 +10:00
Stephen Horvath
a31f851707 More changes for Flathub submission 2025-09-27 18:21:11 +10:00
Stephen Horvath
70d3788dd6 Add sensors to Hardware/Sensors page 2025-09-23 12:54:51 +10:00
Stephen Horvath
f3b74ccc02 Rework advanced LEDs 2025-09-21 22:30:24 +10:00
Stephen Horvath
335a0881b3 Preparation for Flathub publishing 2025-09-21 13:37:35 +10:00
Stephen Horvath
c39a88b7db Remove hard edges from logo 2025-09-19 13:36:33 +10:00
Stephen Horvath
ba78392b24 Add Windows ZIP build 2025-09-18 15:15:55 +10:00
Stephen Horvath
c1205c7661 Add board model to debug info 2025-09-17 21:48:34 +10:00
Stephen Horvath
973ff26fa7 Fix stutter when opening About dialogue 2025-09-17 21:48:06 +10:00
Stephen Horvath
4a8dfbad47 Update flatpak versioning 2025-09-17 17:19:58 +10:00
Stephen Horvath
2a0675d3be Fix pyinstaller for CI and Windows 2025-09-17 16:51:33 +10:00
Stephen Horvath
55580535db Add new logo and splash screen 2025-09-17 16:26:21 +10:00
41 changed files with 993 additions and 350 deletions

2
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,2 @@
github: [Steve-Tech]
thanks_dev: u/gh/steve-tech

View File

@@ -8,10 +8,10 @@ jobs:
flatpak: flatpak:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-48 image: ghcr.io/flathub-infra/flatpak-github-actions:gnome-50
options: --privileged options: --privileged
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v6
- name: Build Flatpak - name: Build Flatpak
uses: flatpak/flatpak-github-actions/flatpak-builder@v6 uses: flatpak/flatpak-github-actions/flatpak-builder@v6
with: with:

View File

@@ -8,12 +8,12 @@ jobs:
pyinstaller-linux: pyinstaller-linux:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v6
# We shouldn't use actions/setup-python since PyGObject is compiled against the system Python # We shouldn't use actions/setup-python since PyGObject is compiled against the system Python
- name: Install System Dependencies - name: Install System Dependencies
uses: awalsh128/cache-apt-pkgs-action@latest uses: awalsh128/cache-apt-pkgs-action@latest
with: with:
packages: python3-gi gir1.2-gtk-4.0 gir1.2-adw-1 libglib2.0-bin packages: python3-gi gir1.2-gtk-4.0 gir1.2-adw-1 libglib2.0-bin python3-tk
version: 0 version: 0
- name: Install PyInstaller - name: Install PyInstaller
run: pip install pyinstaller run: pip install pyinstaller
@@ -21,10 +21,10 @@ jobs:
run: pip install . run: pip install .
- name: Build with PyInstaller - name: Build with PyInstaller
# pyinstaller doesn't find the GTK libraries after caching? # pyinstaller doesn't find the GTK libraries after caching?
run: LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu pyinstaller yafi.spec run: LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu pyinstaller yafi.spec -- --onefile
working-directory: pyinstaller working-directory: pyinstaller
- name: Upload PyInstaller Artifact - name: Upload PyInstaller Artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v6
with: with:
path: pyinstaller/dist/YAFI path: pyinstaller/dist/YAFI
name: yafi-linux-${{ github.sha }} name: yafi-linux-${{ github.sha }}

View File

@@ -8,22 +8,22 @@ jobs:
pyinstaller-windows: pyinstaller-windows:
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v6
- uses: actions/setup-python@v5 - uses: actions/setup-python@v6
with: with:
python-version: '3.13' python-version: '3.14'
cache: 'pip' cache: 'pip'
- name: Cache GTK4 - name: Cache GTK4
id: cache-gtk4 id: cache-gtk4
uses: actions/cache@v4 uses: actions/cache@v5
with: with:
path: C:\gtk path: C:\gtk
key: Gvsbuild_2025.8.0 key: Gvsbuild_2026.2.0
- name: Download GTK4 Gvsbuild zip - name: Download GTK4 Gvsbuild zip
if: steps.cache-gtk4.outputs.cache-hit != 'true' if: steps.cache-gtk4.outputs.cache-hit != 'true'
run: Start-BitsTransfer -Source https://github.com/wingtk/gvsbuild/releases/download/2025.8.0/GTK4_Gvsbuild_2025.8.0_x64.zip -Destination Gvsbuild.zip run: Start-BitsTransfer -Source https://github.com/wingtk/gvsbuild/releases/download/2026.2.0/GTK4_Gvsbuild_2026.2.0_x64.zip -Destination Gvsbuild.zip
- name: Extract Gvsbuild zip - name: Extract Gvsbuild zip
if: steps.cache-gtk4.outputs.cache-hit != 'true' if: steps.cache-gtk4.outputs.cache-hit != 'true'
@@ -41,12 +41,22 @@ jobs:
- name: Build YAFI via Pip - name: Build YAFI via Pip
run: pip install . run: pip install .
- name: Build with PyInstaller - name: Build with PyInstaller (ZIP)
run: python -m PyInstaller yafi.spec run: python -m PyInstaller yafi.spec
working-directory: pyinstaller working-directory: pyinstaller
- name: Upload PyInstaller Artifact - name: Upload PyInstaller Artifact (ZIP)
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v6
with:
path: pyinstaller/dist/YAFI/*
name: yafi-windows-${{ github.sha }}
- name: Build with PyInstaller (Standalone)
run: python -m PyInstaller yafi.spec --noconfirm -- --onefile
working-directory: pyinstaller
- name: Upload PyInstaller Artifact (Standalone)
uses: actions/upload-artifact@v6
with: with:
path: pyinstaller/dist/YAFI.exe path: pyinstaller/dist/YAFI.exe
name: yafi-windows-${{ github.sha }} name: yafi-windows-standalone-${{ github.sha }}

View File

@@ -1,7 +0,0 @@
# CrOS_EC_Python udev rules
# LPC Access
KERNEL=="port", TAG+="uaccess"
# /dev/cros_ec Access
KERNEL=="cros_ec", TAG+="uaccess"

View File

@@ -11,9 +11,13 @@ You can download the latest release from the [Releases page](https://github.com/
There are builds for Flatpak, and PyInstaller for portable execution on Linux or Windows. There are builds for Flatpak, and PyInstaller for portable execution on Linux or Windows.
YAFI is also available on [Flathub](https://flathub.org/en/apps/au.stevetech.yafi): `flatpak install flathub au.stevetech.yafi`.
### Linux ### Linux
To allow YAFI to communicate with the EC, you need to copy the [`60-cros_ec_python.rules`](60-cros_ec_python.rules) file to `/etc/udev/rules.d/` and reload the rules with `sudo udevadm control --reload-rules && sudo udevadm trigger`. To allow YAFI to communicate with the EC, you will need to enable user access to the `/dev/cros_ec` device. You can do this by running `echo KERNEL==\"cros_ec\", TAG+=\"uaccess\" | sudo tee /etc/udev/rules.d/60-yafi.rules`, and then reload the rules with `sudo udevadm control --reload-rules && sudo udevadm trigger`.
You can also do this by running `curl -Lfs yafi.stevetech.au/udev.sh | sudo sh` which will run the [`add-udev-rules.sh`](add-udev-rules.sh) script.
### Windows ### Windows
@@ -80,7 +84,7 @@ It is possible to run YAFI on Windows using [gvsbuild](https://github.com/wingtk
### `[Errno 13] Permission denied: '/dev/cros_ec'` ### `[Errno 13] Permission denied: '/dev/cros_ec'`
This error occurs when the udev rules are not installed or not working. Make sure you have copied the `60-cros_ec_python.rules` file to `/etc/udev/rules.d/` and reloaded the rules with `sudo udevadm control --reload-rules && sudo udevadm trigger`. This error occurs when the udev rules are not installed or not working. Make sure you have installed the udev rules as described in the [Linux Installation](#linux) section.
### `Could not auto detect device, check you have the required permissions, or specify manually.` ### `Could not auto detect device, check you have the required permissions, or specify manually.`
@@ -88,3 +92,9 @@ This error occurs when `/dev/cros_ec` is not found, and the `CrOS_EC_Python` lib
You can either update your kernel to have a working `cros_ec_dev` driver, or run YAFI as root. You can either update your kernel to have a working `cros_ec_dev` driver, or run YAFI as root.
It can also occur if you do not have a CrOS EC, like on non Framework laptops. It can also occur if you do not have a CrOS EC, like on non Framework laptops.
## Disclaimer
YAFI is not affiliated with Framework Computer Inc. in any way.
YAFI is licensed under the [GPL-2.0-or-later license](COPYING), and comes with no warranty or guarantee of any kind. Use at your own risk.

7
add-udev-rules.sh Executable file
View File

@@ -0,0 +1,7 @@
#!/bin/bash
set -e
echo Installing udev rules for YAFI to /etc/udev/rules.d/60-yafi.rules
echo KERNEL==\"cros_ec\", TAG+=\"uaccess\" > /etc/udev/rules.d/60-yafi.rules
udevadm control --reload-rules
udevadm trigger
echo udev rules installed successfully.

View File

@@ -1,13 +1,14 @@
{ {
"id" : "au.stevetech.yafi", "id" : "au.stevetech.yafi",
"runtime" : "org.gnome.Platform", "runtime" : "org.gnome.Platform",
"runtime-version" : "48", "runtime-version" : "49",
"sdk" : "org.gnome.Sdk", "sdk" : "org.gnome.Sdk",
"command" : "yafi", "command" : "yafi",
"finish-args" : [ "finish-args" : [
"--device=all", "--device=all",
"--socket=fallback-x11", "--socket=fallback-x11",
"--socket=wayland" "--socket=wayland",
"--share=ipc"
], ],
"cleanup" : [ "cleanup" : [
"/include", "/include",
@@ -21,6 +22,7 @@
"*.a" "*.a"
], ],
"modules" : [ "modules" : [
"python3-cros_ec_python.json",
{ {
"name" : "yafi", "name" : "yafi",
"builddir" : true, "builddir" : true,
@@ -31,18 +33,6 @@
"path" : "." "path" : "."
} }
] ]
},
{
"name": "cros_ec_python",
"buildsystem": "simple",
"build-options": {
"build-args": [
"--share=network"
]
},
"build-commands": [
"pip3 install --prefix=${FLATPAK_DEST} --no-cache-dir \"cros_ec_python>=0.2.0\""
]
} }
] ]
} }

View File

@@ -6,6 +6,6 @@ Comment=Yet Another Framework Interface
Terminal=false Terminal=false
Type=Application Type=Application
Categories=Utility; Categories=Utility;
Keywords=GTK; Keywords=Framework;EC;Embedded Controller;
StartupNotify=true StartupNotify=true
DBusActivatable=true DBusActivatable=true

View File

@@ -7,11 +7,25 @@
<name>Yet Another Framework Interface</name> <name>Yet Another Framework Interface</name>
<summary>YAFI is another GUI for the Framework Laptop Embedded Controller</summary> <summary>YAFI is another GUI for the Framework Laptop Embedded Controller</summary>
<description> <description>
<p>It is written in Python with a GTK3 theme, and uses the `CrOS_EC_Python` library to communicate with the EC.</p> <p>It is written in Python with a GTK4 Adwaita theme, and uses the CrOS_EC_Python library to communicate with the EC.</p>
<p>YAFI has the capability for the following features:</p>
<ul>
<li>Fan control and temperature monitoring</li>
<li>LED control</li>
<li>Battery statistics</li>
<li>Battery limiting</li>
<li>Hardware information</li>
</ul>
<p>You will need to install the udev rules to allow non-root access to the EC device. See the README for more information.</p>
<p>Alternatively, you can run <code>curl -Lfs yafi.stevetech.au/udev.sh | sudo sh</code> to install the udev rules.</p>
<p>YAFI is not affiliated with Framework Computer Inc. in any way.</p>
</description> </description>
<developer id="au.stevetech"> <developer id="au.stevetech">
<name>Stephen Horvath</name> <name translate="no">Stephen Horvath</name>
</developer> </developer>
<!-- Required: Should be a link to the upstream homepage for the component --> <!-- Required: Should be a link to the upstream homepage for the component -->
@@ -27,7 +41,7 @@
<!-- Should provide a web link to an online user's reference, a software manual or help page --> <!-- Should provide a web link to an online user's reference, a software manual or help page -->
<!-- <url type="help">https://example.org/help</url> --> <!-- <url type="help">https://example.org/help</url> -->
<!-- URLs of this type should point to a webpage showing information on how to donate to the described software project --> <!-- URLs of this type should point to a webpage showing information on how to donate to the described software project -->
<!-- <url type="donation">https://example.org/donate</url> --> <url type="donation">https://github.com/sponsors/Steve-Tech</url>
<!-- This could for example be an HTTPS URL to an online form or a page describing how to contact the developer --> <!-- This could for example be an HTTPS URL to an online form or a page describing how to contact the developer -->
<!-- <url type="contact">https://example.org/contact</url> --> <!-- <url type="contact">https://example.org/contact</url> -->
<!-- URLs of this type should point to a webpage showing information on how to contribute to the described software project --> <!-- URLs of this type should point to a webpage showing information on how to contribute to the described software project -->
@@ -42,42 +56,104 @@
<!-- Applications should set a brand color in both light and dark variants like so --> <!-- Applications should set a brand color in both light and dark variants like so -->
<branding> <branding>
<color type="primary" scheme_preference="light">#ff00ff</color> <color type="primary" scheme_preference="light">#7c916f</color>
<color type="primary" scheme_preference="dark">#993d3d</color> <color type="primary" scheme_preference="dark">#282000</color>
</branding> </branding>
<screenshots> <screenshots>
<screenshot type="default"> <screenshot type="default">
<image>https://github.com/Steve-Tech/YAFI/blob/main/docs/1-thermal.png</image> <image>https://raw.githubusercontent.com/Steve-Tech/YAFI/refs/heads/main/docs/1-thermals.png</image>
<caption>The Thermal page</caption> <caption>Fan Control and Temperature Monitoring</caption>
</screenshot> </screenshot>
<screenshot> <screenshot>
<image>https://github.com/Steve-Tech/YAFI/blob/main/docs/2-leds.png</image> <image>https://raw.githubusercontent.com/Steve-Tech/YAFI/refs/heads/main/docs/2-leds.png</image>
<caption>The LED page</caption> <caption>LED Control</caption>
</screenshot> </screenshot>
<screenshot> <screenshot>
<image>https://github.com/Steve-Tech/YAFI/blob/main/docs/3-battery.png</image> <image>https://raw.githubusercontent.com/Steve-Tech/YAFI/refs/heads/main/docs/3-battery.png</image>
<caption>The Battery page</caption> <caption>Battery Statistics</caption>
</screenshot> </screenshot>
<screenshot> <screenshot>
<image>https://github.com/Steve-Tech/YAFI/blob/main/docs/4-hardware.png</image> <image>https://raw.githubusercontent.com/Steve-Tech/YAFI/refs/heads/main/docs/4-battery-limit.png</image>
<caption>The Hardware page</caption> <caption>Battery Limiting</caption>
</screenshot>
<screenshot>
<image>https://raw.githubusercontent.com/Steve-Tech/YAFI/refs/heads/main/docs/4a-battery-ext.png</image>
<caption>Battery Extender</caption>
</screenshot>
<screenshot>
<image>https://raw.githubusercontent.com/Steve-Tech/YAFI/refs/heads/main/docs/5-hardware.png</image>
<caption>Hardware Info</caption>
</screenshot> </screenshot>
</screenshots> </screenshots>
<releases> <releases>
<release version="0.1.0" date="2025-03-20"> <release version="1.0" date="2026-03-21">
<url type="details">https://github.com/Steve-Tech/YAFI/releases/tag/0.1.0</url> <url type="details">https://github.com/Steve-Tech/YAFI/releases/tag/1.0</url>
<description translate="no"> <description>
<p>First release</p> <p>The following changes have been made:</p>
<ul> <ul>
<li>Added Thermal page</li> <li>New logo matching the GNOME style!</li>
<li>Added LED page</li> <li>Errored temperature sensors will now show as 'Error'.</li>
<li>Added Battery page</li> <li>Fix for battery page when battery isn't present.</li>
<li>Added Hardware page</li> <li>Fix some minor UI bugs.</li>
</ul> </ul>
</description> </description>
</release> </release>
<release version="0.7" date="2025-12-25">
<url type="details">https://github.com/Steve-Tech/YAFI/releases/tag/0.7</url>
<description>
<p>YAFI now supports modifying fan set points.</p>
</description>
</release>
<release version="0.6" date="2025-09-28">
<url type="details">https://github.com/Steve-Tech/YAFI/releases/tag/0.6</url>
<description>
<p>The following changes have been made:</p>
<ul>
<li>YAFI now has a new logo!</li>
<li>The advanced LED settings now detect available LEDs.</li>
<li>The ALS and lid open sensor has been added.</li>
<li>Stuttering has been reduced when opening the about dialog.</li>
</ul>
</description>
</release>
<release version="0.5" date="2025-09-16">
<url type="details">https://github.com/Steve-Tech/YAFI/releases/tag/0.5</url>
<description>
<p>The following bugs have been fixed:</p>
<ul>
<li>LED page crashing when encountering unsupported LEDs.</li>
<li>Scaling issues on Windows.</li>
<li>Minimum charge limiter doesn't work.</li>
</ul>
<p>This release also adds a traceback to the debug info, when there is an error during initialisation.</p>
</description>
</release>
<release version="0.4" date="2025-09-06">
<url type="details">https://github.com/Steve-Tech/YAFI/releases/tag/0.4</url>
<description>
<p>This release also adds a new battery statistics page.</p>
</description>
</release>
<release version="0.3" date="2025-04-13">
<url type="details">https://github.com/Steve-Tech/YAFI/releases/tag/0.3</url>
<description>
<p>YAFI now shows the battery limiter value.</p>
</description>
</release>
<release version="0.2" date="2025-03-24">
<url type="details">https://github.com/Steve-Tech/YAFI/releases/tag/0.2</url>
<description>
<p>This fixes an LED list bug.</p>
</description>
</release>
<release version="0.1" date="2025-03-20">
<url type="details">https://github.com/Steve-Tech/YAFI/releases/tag/0.1</url>
<description>
<p>This is the first release of YAFI.</p>
</description>
</release>
</releases> </releases>
</component> </component>

View File

@@ -1,36 +1,92 @@
<?xml version="1.0" standalone="no"?> <svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" <rect x="12" y="92" width="104" height="24" rx="8" fill="url(#paint0_linear_293_18)"/>
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <rect x="12" y="88" width="104" height="24" rx="8" fill="#328361"/>
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" <rect x="12" y="88" width="104" height="24" rx="8" fill="url(#paint1_linear_293_18)" fill-opacity="0.5" style="mix-blend-mode:multiply"/>
width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000" <path d="M108 12H20C15.5817 12 12 15.5817 12 20V24V33V102C12 106.418 15.5817 110 20 110H108C112.418 110 116 106.418 116 102V20C116 15.5817 112.418 12 108 12Z" fill="#3FB182"/>
preserveAspectRatio="xMidYMid meet"> <path d="M34 25H38V18C38 17.4477 37.5523 17 37 17H35C34.4477 17 34 17.4477 34 18V25Z" fill="#FFE11D"/>
<metadata> <path d="M42 25H46V18C46 17.4477 45.5523 17 45 17H43C42.4477 17 42 17.4477 42 18V25Z" fill="#FFE11D"/>
Created by potrace 1.11, written by Peter Selinger 2001-2013 <path d="M50 25H54V18C54 17.4477 53.5523 17 53 17H51C50.4477 17 50 17.4477 50 18V25Z" fill="#FFE11D"/>
</metadata> <path d="M58 25H62V18C62 17.4477 61.5523 17 61 17H59C58.4477 17 58 17.4477 58 18V25Z" fill="#FFE11D"/>
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)" <path d="M66 25H70V18C70 17.4477 69.5523 17 69 17H67C66.4477 17 66 17.4477 66 18V25Z" fill="#FFE11D"/>
fill="#000000" stroke="none"> <path d="M74 25H78V18C78 17.4477 77.5523 17 77 17H75C74.4477 17 74 17.4477 74 18V25Z" fill="#FFE11D"/>
<path d="M1755 4883 c-120 -22 -418 -180 -609 -322 -118 -89 -148 -118 -177 <path d="M82 25H86V18C86 17.4477 85.5523 17 85 17H83C82.4477 17 82 17.4477 82 18V25Z" fill="#FFE11D"/>
-177 -23 -48 -24 -57 -27 -314 -1 -146 -7 -294 -13 -330 -18 -110 -78 -222 <path d="M90 25H94V18C94 17.4477 93.5523 17 93 17H91C90.4477 17 90 17.4477 90 18V25Z" fill="#FFE11D"/>
-163 -303 -46 -43 -69 -58 -305 -197 -191 -112 -222 -139 -257 -214 -33 -73 <rect x="24" y="27" width="80" height="74" rx="8" fill="url(#paint2_linear_293_18)"/>
-39 -145 -39 -461 0 -297 5 -360 33 -440 25 -73 77 -118 257 -224 88 -51 187 <rect x="24" y="27" width="80" height="74" rx="8" fill="black" fill-opacity="0.1"/>
-111 220 -132 123 -79 192 -169 245 -319 8 -21 14 -110 16 -230 8 -403 9 -423 <rect x="24" y="21" width="80" height="72" rx="8" fill="#EAEAEA"/>
29 -460 32 -61 56 -88 134 -148 234 -181 550 -347 676 -356 75 -5 116 12 306 <path d="M34 98C34 96.8954 34.8954 96 36 96C37.1046 96 38 96.8954 38 98V105C38 105.552 37.5523 106 37 106H35C34.4477 106 34 105.552 34 105V98Z" fill="#939A00"/>
125 181 108 307 175 330 176 8 1 35 5 61 11 70 14 174 5 251 -23 38 -13 164 <path d="M42 98C42 96.8954 42.8954 96 44 96C45.1046 96 46 96.8954 46 98V105C46 105.552 45.5523 106 45 106H43C42.4477 106 42 105.552 42 105V98Z" fill="#939A00"/>
-81 281 -149 286 -168 312 -173 494 -90 41 19 75 34 77 34 4 0 201 110 243 <path d="M50 98C50 96.8954 50.8954 96 52 96C53.1046 96 54 96.8954 54 98V105C54 105.552 53.5523 106 53 106H51C50.4477 106 50 105.552 50 105V98Z" fill="#939A00"/>
135 45 27 147 100 213 153 51 40 83 75 104 113 l30 54 6 310 c5 280 8 315 27 <path d="M58 98C58 96.8954 58.8954 96 60 96C61.1046 96 62 96.8954 62 98V105C62 105.552 61.5523 106 61 106H59C58.4477 106 58 105.552 58 105V98Z" fill="#939A00"/>
365 58 156 137 245 295 336 246 140 346 205 376 243 35 44 60 106 67 166 2 22 <path d="M66 98C66 96.8954 66.8954 96 68 96C69.1046 96 70 96.8954 70 98V105C70 105.552 69.5523 106 69 106H67C66.4477 106 66 105.552 66 105V98Z" fill="#939A00"/>
8 74 13 115 9 78 7 442 -4 520 -12 97 -16 116 -27 150 -16 52 -61 113 -105 <path d="M74 98C74 96.8954 74.8954 96 76 96C77.1046 96 78 96.8954 78 98V105C78 105.552 77.5523 106 77 106H75C74.4477 106 74 105.552 74 105V98Z" fill="#939A00"/>
142 -21 14 -126 78 -233 141 -107 64 -209 128 -225 144 -51 48 -101 115 -128 <path d="M82 98C82 96.8954 82.8954 96 84 96C85.1046 96 86 96.8954 86 98V105C86 105.552 85.5523 106 85 106H83C82.4477 106 82 105.552 82 105V98Z" fill="#939A00"/>
173 -48 105 -56 163 -56 454 -1 262 -1 270 -25 321 -24 53 -65 100 -124 145 <path d="M90 98C90 96.8954 90.8954 96 92 96C93.1046 96 94 96.8954 94 98V105C94 105.552 93.5523 106 93 106H91C90.4477 106 90 105.552 90 105V98Z" fill="#939A00"/>
-19 14 -46 34 -60 46 -42 32 -190 128 -257 164 -250 138 -384 177 -476 140 <path d="M34 98C34 96.8954 34.8954 96 36 96C37.1046 96 38 96.8954 38 98V104H34V98Z" fill="#FFE11D"/>
-19 -8 -101 -54 -184 -104 -316 -188 -340 -198 -480 -199 -153 -1 -181 10 <path d="M42 98C42 96.8954 42.8954 96 44 96C45.1046 96 46 96.8954 46 98V104H42V98Z" fill="#FFE11D"/>
-501 201 -178 106 -237 128 -309 115z m984 -848 c149 -19 308 -68 441 -135 68 <path d="M50 98C50 96.8954 50.8954 96 52 96C53.1046 96 54 96.8954 54 98V104H50V98Z" fill="#FFE11D"/>
-34 181 -100 190 -110 3 -3 21 -17 40 -30 52 -37 75 -57 166 -148 150 -151 <path d="M58 98C58 96.8954 58.8954 96 60 96C61.1046 96 62 96.8954 62 98V104H58V98Z" fill="#FFE11D"/>
281 -364 345 -562 33 -102 32 -99 56 -210 18 -86 26 -378 13 -455 -5 -27 -12 <path d="M66 98C66 96.8954 66.8954 96 68 96C69.1046 96 70 96.8954 70 98V104H66V98Z" fill="#FFE11D"/>
-68 -15 -90 -16 -102 -64 -250 -117 -364 -211 -450 -634 -764 -1113 -828 -113 <path d="M74 98C74 96.8954 74.8954 96 76 96C77.1046 96 78 96.8954 78 98V104H74V98Z" fill="#FFE11D"/>
-15 -425 -7 -455 12 -4 2 -22 7 -41 10 -150 26 -404 140 -531 239 -14 12 -41 <path d="M82 98C82 96.8954 82.8954 96 84 96C85.1046 96 86 96.8954 86 98V104H82V98Z" fill="#FFE11D"/>
32 -59 46 -115 85 -291 299 -371 449 -78 148 -144 353 -165 516 -10 76 -10 <path d="M90 98C90 96.8954 90.8954 96 92 96C93.1046 96 94 96.8954 94 98V104H90V98Z" fill="#FFE11D"/>
311 0 390 15 117 58 274 106 390 116 278 347 543 608 696 158 92 386 169 549 <path d="M34 98C34 96.8954 34.8954 96 36 96C37.1046 96 38 96.8954 38 98H34Z" fill="#808080"/>
184 38 4 70 8 72 9 5 6 229 -2 281 -9z"/> <path d="M42 98C42 96.8954 42.8954 96 44 96C45.1046 96 46 96.8954 46 98H42Z" fill="#808080"/>
<path d="M50 98C50 96.8954 50.8954 96 52 96C53.1046 96 54 96.8954 54 98H50Z" fill="#808080"/>
<path d="M58 98C58 96.8954 58.8954 96 60 96C61.1046 96 62 96.8954 62 98H58Z" fill="#808080"/>
<path d="M66 98C66 96.8954 66.8954 96 68 96C69.1046 96 70 96.8954 70 98H66Z" fill="#808080"/>
<path d="M74 98C74 96.8954 74.8954 96 76 96C77.1046 96 78 96.8954 78 98H74Z" fill="#808080"/>
<path d="M82 98C82 96.8954 82.8954 96 84 96C85.1046 96 86 96.8954 86 98H82Z" fill="#808080"/>
<path d="M90 98C90 96.8954 90.8954 96 92 96C93.1046 96 94 96.8954 94 98H90Z" fill="#808080"/>
<g filter="url(#filter0_i_293_18)">
<path d="M48.8658 38.6343C49.4695 35.7019 52.4974 33.9536 55.3388 34.8971L57.6974 35.6803C61.7893 37.039 66.2107 37.039 70.3026 35.6803L72.6612 34.8971C75.5026 33.9536 78.5305 35.7018 79.1342 38.6343L79.6352 41.0684C80.5045 45.2915 82.7152 49.1206 85.9378 51.9849L87.7953 53.6359C90.0331 55.6249 90.0331 59.1213 87.7953 61.1103L85.9378 62.7612C82.7152 65.6256 80.5045 69.4546 79.6352 73.6777L79.1342 76.1118C78.5305 79.0443 75.5026 80.7925 72.6612 79.849L70.3026 79.0659C66.2107 77.7071 61.7893 77.7071 57.6974 79.0659L55.3388 79.849C52.4974 80.7925 49.4695 79.0443 48.8658 76.1118L48.3648 73.6777C47.4955 69.4547 45.2848 65.6256 42.0622 62.7612L40.2047 61.1103C37.9669 59.1213 37.9669 55.6249 40.2047 53.6359L42.0622 51.9849C45.2848 49.1206 47.4955 45.2915 48.3648 41.0684L48.8658 38.6343Z" fill="#D9D9D9"/>
<path d="M48.8658 38.6343C49.4695 35.7019 52.4974 33.9536 55.3388 34.8971L57.6974 35.6803C61.7893 37.039 66.2107 37.039 70.3026 35.6803L72.6612 34.8971C75.5026 33.9536 78.5305 35.7018 79.1342 38.6343L79.6352 41.0684C80.5045 45.2915 82.7152 49.1206 85.9378 51.9849L87.7953 53.6359C90.0331 55.6249 90.0331 59.1213 87.7953 61.1103L85.9378 62.7612C82.7152 65.6256 80.5045 69.4546 79.6352 73.6777L79.1342 76.1118C78.5305 79.0443 75.5026 80.7925 72.6612 79.849L70.3026 79.0659C66.2107 77.7071 61.7893 77.7071 57.6974 79.0659L55.3388 79.849C52.4974 80.7925 49.4695 79.0443 48.8658 76.1118L48.3648 73.6777C47.4955 69.4547 45.2848 65.6256 42.0622 62.7612L40.2047 61.1103C37.9669 59.1213 37.9669 55.6249 40.2047 53.6359L42.0622 51.9849C45.2848 49.1206 47.4955 45.2915 48.3648 41.0684L48.8658 38.6343Z" fill="#202020"/>
</g> </g>
<g filter="url(#filter1_d_293_18)">
<path d="M64 70C56.8216 70 51 64.1761 51 57C51 49.8194 56.8216 44 64 44C71.1784 44 77 49.8239 77 57C77 64.1761 71.1784 70 64 70Z" fill="#EAEAEA"/>
</g>
<defs>
<filter id="filter0_i_293_18" x="38.5264" y="34.6403" width="50.9473" height="45.4655" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.501961 0 0 0 0 0.501961 0 0 0 0 0.501961 0 0 0 1 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_293_18"/>
</filter>
<filter id="filter1_d_293_18" x="51" y="44" width="26" height="28" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.501961 0 0 0 0 0.501961 0 0 0 0 0.501961 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_293_18"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_293_18" result="shape"/>
</filter>
<linearGradient id="paint0_linear_293_18" x1="116" y1="116" x2="12" y2="116" gradientUnits="userSpaceOnUse">
<stop stop-color="#404040"/>
<stop offset="0.03" stop-color="#D0D0D0"/>
<stop offset="0.06" stop-color="#606060"/>
<stop offset="0.94" stop-color="#606060"/>
<stop offset="0.97" stop-color="#D0D0D0"/>
<stop offset="1" stop-color="#404040"/>
</linearGradient>
<linearGradient id="paint1_linear_293_18" x1="116" y1="112" x2="12" y2="112" gradientUnits="userSpaceOnUse">
<stop stop-color="#404040"/>
<stop offset="0.03" stop-color="#D0D0D0"/>
<stop offset="0.06" stop-color="#606060"/>
<stop offset="0.94" stop-color="#606060"/>
<stop offset="0.97" stop-color="#D0D0D0"/>
<stop offset="1" stop-color="#404040"/>
</linearGradient>
<linearGradient id="paint2_linear_293_18" x1="24" y1="85.8476" x2="103.999" y2="85.6325" gradientUnits="userSpaceOnUse">
<stop stop-color="#AFAFAF"/>
<stop offset="0.04" stop-color="#F6F5F4"/>
<stop offset="0.08" stop-color="#D0D0D0"/>
<stop offset="0.92" stop-color="#D0D0D0"/>
<stop offset="0.96" stop-color="#F6F5F4"/>
<stop offset="1" stop-color="#AFAFAF"/>
</linearGradient>
</defs>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -1,36 +1,4 @@
<?xml version="1.0" standalone="no"?> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" <path d="M8 10C6.89563 10 6 9.10402 6 8C6 6.8953 6.89563 6 8 6C9.10437 6 10 6.89598 10 8C10 9.10402 9.10437 10 8 10Z" fill="black"/>
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <path fill-rule="evenodd" clip-rule="evenodd" d="M0 2C0 0.895431 0.895431 0 2 0H3V1C3 1.55228 3.44772 2 4 2C4.55228 2 5 1.55228 5 1V0H7V1C7 1.55228 7.44772 2 8 2C8.55228 2 9 1.55228 9 1V0H11V1C11 1.55228 11.4477 2 12 2C12.5523 2 13 1.55228 13 1V0H14C15.1046 0 16 0.895431 16 2V14C16 15.1046 15.1046 16 14 16H13V15C13 14.4477 12.5523 14 12 14C11.4477 14 11 14.4477 11 15V16H9V15C9 14.4477 8.55228 14 8 14C7.44772 14 7 14.4477 7 15V16H5V15C5 14.4477 4.55228 14 4 14C3.44772 14 3 14.4477 3 15V16H2C0.895431 16 0 15.1046 0 14V2ZM5.23026 4.85673C5.04181 5.76259 4.56253 6.58395 3.86386 7.19836C3.37871 7.625 3.37871 8.375 3.86386 8.80164C4.56253 9.41605 5.04181 10.2374 5.23026 11.1433C5.36113 11.7723 6.01759 12.1473 6.6336 11.9449C7.52072 11.6535 8.47928 11.6535 9.3664 11.9449C9.98241 12.1473 10.6389 11.7723 10.7697 11.1433C10.9582 10.2374 11.4375 9.41605 12.1361 8.80164C12.6213 8.375 12.6213 7.625 12.1361 7.19836C11.4375 6.58395 10.9582 5.76259 10.7697 4.85673C10.6389 4.2277 9.98241 3.85271 9.3664 4.05509C8.47928 4.34654 7.52072 4.34654 6.6336 4.05509C6.01759 3.85271 5.36113 4.2277 5.23026 4.85673ZM8 10C6.89563 10 6 9.10402 6 8C6 6.8953 6.89563 6 8 6C9.10437 6 10 6.89598 10 8C10 9.10402 9.10437 10 8 10Z" fill="black"/>
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="512.000000pt" height="512.000000pt" viewBox="0 0 512.000000 512.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.11, written by Peter Selinger 2001-2013
</metadata>
<g transform="translate(0.000000,512.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M1755 4883 c-120 -22 -418 -180 -609 -322 -118 -89 -148 -118 -177
-177 -23 -48 -24 -57 -27 -314 -1 -146 -7 -294 -13 -330 -18 -110 -78 -222
-163 -303 -46 -43 -69 -58 -305 -197 -191 -112 -222 -139 -257 -214 -33 -73
-39 -145 -39 -461 0 -297 5 -360 33 -440 25 -73 77 -118 257 -224 88 -51 187
-111 220 -132 123 -79 192 -169 245 -319 8 -21 14 -110 16 -230 8 -403 9 -423
29 -460 32 -61 56 -88 134 -148 234 -181 550 -347 676 -356 75 -5 116 12 306
125 181 108 307 175 330 176 8 1 35 5 61 11 70 14 174 5 251 -23 38 -13 164
-81 281 -149 286 -168 312 -173 494 -90 41 19 75 34 77 34 4 0 201 110 243
135 45 27 147 100 213 153 51 40 83 75 104 113 l30 54 6 310 c5 280 8 315 27
365 58 156 137 245 295 336 246 140 346 205 376 243 35 44 60 106 67 166 2 22
8 74 13 115 9 78 7 442 -4 520 -12 97 -16 116 -27 150 -16 52 -61 113 -105
142 -21 14 -126 78 -233 141 -107 64 -209 128 -225 144 -51 48 -101 115 -128
173 -48 105 -56 163 -56 454 -1 262 -1 270 -25 321 -24 53 -65 100 -124 145
-19 14 -46 34 -60 46 -42 32 -190 128 -257 164 -250 138 -384 177 -476 140
-19 -8 -101 -54 -184 -104 -316 -188 -340 -198 -480 -199 -153 -1 -181 10
-501 201 -178 106 -237 128 -309 115z m984 -848 c149 -19 308 -68 441 -135 68
-34 181 -100 190 -110 3 -3 21 -17 40 -30 52 -37 75 -57 166 -148 150 -151
281 -364 345 -562 33 -102 32 -99 56 -210 18 -86 26 -378 13 -455 -5 -27 -12
-68 -15 -90 -16 -102 -64 -250 -117 -364 -211 -450 -634 -764 -1113 -828 -113
-15 -425 -7 -455 12 -4 2 -22 7 -41 10 -150 26 -404 140 -531 239 -14 12 -41
32 -59 46 -115 85 -291 299 -371 449 -78 148 -144 353 -165 516 -10 76 -10
311 0 390 15 117 58 274 106 390 116 278 347 543 608 696 158 92 386 169 549
184 38 4 70 8 72 9 5 6 229 -2 281 -9z"/>
</g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 KiB

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 103 KiB

3
flathub.json Normal file
View File

@@ -0,0 +1,3 @@
{
"only-arches": ["x86_64"]
}

92
logo.svg Normal file
View File

@@ -0,0 +1,92 @@
<svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="12" y="92" width="104" height="24" rx="8" fill="url(#paint0_linear_293_18)"/>
<rect x="12" y="88" width="104" height="24" rx="8" fill="#328361"/>
<rect x="12" y="88" width="104" height="24" rx="8" fill="url(#paint1_linear_293_18)" fill-opacity="0.5" style="mix-blend-mode:multiply"/>
<path d="M108 12H20C15.5817 12 12 15.5817 12 20V24V33V102C12 106.418 15.5817 110 20 110H108C112.418 110 116 106.418 116 102V20C116 15.5817 112.418 12 108 12Z" fill="#3FB182"/>
<path d="M34 25H38V18C38 17.4477 37.5523 17 37 17H35C34.4477 17 34 17.4477 34 18V25Z" fill="#FFE11D"/>
<path d="M42 25H46V18C46 17.4477 45.5523 17 45 17H43C42.4477 17 42 17.4477 42 18V25Z" fill="#FFE11D"/>
<path d="M50 25H54V18C54 17.4477 53.5523 17 53 17H51C50.4477 17 50 17.4477 50 18V25Z" fill="#FFE11D"/>
<path d="M58 25H62V18C62 17.4477 61.5523 17 61 17H59C58.4477 17 58 17.4477 58 18V25Z" fill="#FFE11D"/>
<path d="M66 25H70V18C70 17.4477 69.5523 17 69 17H67C66.4477 17 66 17.4477 66 18V25Z" fill="#FFE11D"/>
<path d="M74 25H78V18C78 17.4477 77.5523 17 77 17H75C74.4477 17 74 17.4477 74 18V25Z" fill="#FFE11D"/>
<path d="M82 25H86V18C86 17.4477 85.5523 17 85 17H83C82.4477 17 82 17.4477 82 18V25Z" fill="#FFE11D"/>
<path d="M90 25H94V18C94 17.4477 93.5523 17 93 17H91C90.4477 17 90 17.4477 90 18V25Z" fill="#FFE11D"/>
<rect x="24" y="27" width="80" height="74" rx="8" fill="url(#paint2_linear_293_18)"/>
<rect x="24" y="27" width="80" height="74" rx="8" fill="black" fill-opacity="0.1"/>
<rect x="24" y="21" width="80" height="72" rx="8" fill="#EAEAEA"/>
<path d="M34 98C34 96.8954 34.8954 96 36 96C37.1046 96 38 96.8954 38 98V105C38 105.552 37.5523 106 37 106H35C34.4477 106 34 105.552 34 105V98Z" fill="#939A00"/>
<path d="M42 98C42 96.8954 42.8954 96 44 96C45.1046 96 46 96.8954 46 98V105C46 105.552 45.5523 106 45 106H43C42.4477 106 42 105.552 42 105V98Z" fill="#939A00"/>
<path d="M50 98C50 96.8954 50.8954 96 52 96C53.1046 96 54 96.8954 54 98V105C54 105.552 53.5523 106 53 106H51C50.4477 106 50 105.552 50 105V98Z" fill="#939A00"/>
<path d="M58 98C58 96.8954 58.8954 96 60 96C61.1046 96 62 96.8954 62 98V105C62 105.552 61.5523 106 61 106H59C58.4477 106 58 105.552 58 105V98Z" fill="#939A00"/>
<path d="M66 98C66 96.8954 66.8954 96 68 96C69.1046 96 70 96.8954 70 98V105C70 105.552 69.5523 106 69 106H67C66.4477 106 66 105.552 66 105V98Z" fill="#939A00"/>
<path d="M74 98C74 96.8954 74.8954 96 76 96C77.1046 96 78 96.8954 78 98V105C78 105.552 77.5523 106 77 106H75C74.4477 106 74 105.552 74 105V98Z" fill="#939A00"/>
<path d="M82 98C82 96.8954 82.8954 96 84 96C85.1046 96 86 96.8954 86 98V105C86 105.552 85.5523 106 85 106H83C82.4477 106 82 105.552 82 105V98Z" fill="#939A00"/>
<path d="M90 98C90 96.8954 90.8954 96 92 96C93.1046 96 94 96.8954 94 98V105C94 105.552 93.5523 106 93 106H91C90.4477 106 90 105.552 90 105V98Z" fill="#939A00"/>
<path d="M34 98C34 96.8954 34.8954 96 36 96C37.1046 96 38 96.8954 38 98V104H34V98Z" fill="#FFE11D"/>
<path d="M42 98C42 96.8954 42.8954 96 44 96C45.1046 96 46 96.8954 46 98V104H42V98Z" fill="#FFE11D"/>
<path d="M50 98C50 96.8954 50.8954 96 52 96C53.1046 96 54 96.8954 54 98V104H50V98Z" fill="#FFE11D"/>
<path d="M58 98C58 96.8954 58.8954 96 60 96C61.1046 96 62 96.8954 62 98V104H58V98Z" fill="#FFE11D"/>
<path d="M66 98C66 96.8954 66.8954 96 68 96C69.1046 96 70 96.8954 70 98V104H66V98Z" fill="#FFE11D"/>
<path d="M74 98C74 96.8954 74.8954 96 76 96C77.1046 96 78 96.8954 78 98V104H74V98Z" fill="#FFE11D"/>
<path d="M82 98C82 96.8954 82.8954 96 84 96C85.1046 96 86 96.8954 86 98V104H82V98Z" fill="#FFE11D"/>
<path d="M90 98C90 96.8954 90.8954 96 92 96C93.1046 96 94 96.8954 94 98V104H90V98Z" fill="#FFE11D"/>
<path d="M34 98C34 96.8954 34.8954 96 36 96C37.1046 96 38 96.8954 38 98H34Z" fill="#808080"/>
<path d="M42 98C42 96.8954 42.8954 96 44 96C45.1046 96 46 96.8954 46 98H42Z" fill="#808080"/>
<path d="M50 98C50 96.8954 50.8954 96 52 96C53.1046 96 54 96.8954 54 98H50Z" fill="#808080"/>
<path d="M58 98C58 96.8954 58.8954 96 60 96C61.1046 96 62 96.8954 62 98H58Z" fill="#808080"/>
<path d="M66 98C66 96.8954 66.8954 96 68 96C69.1046 96 70 96.8954 70 98H66Z" fill="#808080"/>
<path d="M74 98C74 96.8954 74.8954 96 76 96C77.1046 96 78 96.8954 78 98H74Z" fill="#808080"/>
<path d="M82 98C82 96.8954 82.8954 96 84 96C85.1046 96 86 96.8954 86 98H82Z" fill="#808080"/>
<path d="M90 98C90 96.8954 90.8954 96 92 96C93.1046 96 94 96.8954 94 98H90Z" fill="#808080"/>
<g filter="url(#filter0_i_293_18)">
<path d="M48.8658 38.6343C49.4695 35.7019 52.4974 33.9536 55.3388 34.8971L57.6974 35.6803C61.7893 37.039 66.2107 37.039 70.3026 35.6803L72.6612 34.8971C75.5026 33.9536 78.5305 35.7018 79.1342 38.6343L79.6352 41.0684C80.5045 45.2915 82.7152 49.1206 85.9378 51.9849L87.7953 53.6359C90.0331 55.6249 90.0331 59.1213 87.7953 61.1103L85.9378 62.7612C82.7152 65.6256 80.5045 69.4546 79.6352 73.6777L79.1342 76.1118C78.5305 79.0443 75.5026 80.7925 72.6612 79.849L70.3026 79.0659C66.2107 77.7071 61.7893 77.7071 57.6974 79.0659L55.3388 79.849C52.4974 80.7925 49.4695 79.0443 48.8658 76.1118L48.3648 73.6777C47.4955 69.4547 45.2848 65.6256 42.0622 62.7612L40.2047 61.1103C37.9669 59.1213 37.9669 55.6249 40.2047 53.6359L42.0622 51.9849C45.2848 49.1206 47.4955 45.2915 48.3648 41.0684L48.8658 38.6343Z" fill="#D9D9D9"/>
<path d="M48.8658 38.6343C49.4695 35.7019 52.4974 33.9536 55.3388 34.8971L57.6974 35.6803C61.7893 37.039 66.2107 37.039 70.3026 35.6803L72.6612 34.8971C75.5026 33.9536 78.5305 35.7018 79.1342 38.6343L79.6352 41.0684C80.5045 45.2915 82.7152 49.1206 85.9378 51.9849L87.7953 53.6359C90.0331 55.6249 90.0331 59.1213 87.7953 61.1103L85.9378 62.7612C82.7152 65.6256 80.5045 69.4546 79.6352 73.6777L79.1342 76.1118C78.5305 79.0443 75.5026 80.7925 72.6612 79.849L70.3026 79.0659C66.2107 77.7071 61.7893 77.7071 57.6974 79.0659L55.3388 79.849C52.4974 80.7925 49.4695 79.0443 48.8658 76.1118L48.3648 73.6777C47.4955 69.4547 45.2848 65.6256 42.0622 62.7612L40.2047 61.1103C37.9669 59.1213 37.9669 55.6249 40.2047 53.6359L42.0622 51.9849C45.2848 49.1206 47.4955 45.2915 48.3648 41.0684L48.8658 38.6343Z" fill="#202020"/>
</g>
<g filter="url(#filter1_d_293_18)">
<path d="M64 70C56.8216 70 51 64.1761 51 57C51 49.8194 56.8216 44 64 44C71.1784 44 77 49.8239 77 57C77 64.1761 71.1784 70 64 70Z" fill="#EAEAEA"/>
</g>
<defs>
<filter id="filter0_i_293_18" x="38.5264" y="34.6403" width="50.9473" height="45.4655" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.501961 0 0 0 0 0.501961 0 0 0 0 0.501961 0 0 0 1 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_293_18"/>
</filter>
<filter id="filter1_d_293_18" x="51" y="44" width="26" height="28" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.501961 0 0 0 0 0.501961 0 0 0 0 0.501961 0 0 0 1 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_293_18"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_293_18" result="shape"/>
</filter>
<linearGradient id="paint0_linear_293_18" x1="116" y1="116" x2="12" y2="116" gradientUnits="userSpaceOnUse">
<stop stop-color="#404040"/>
<stop offset="0.03" stop-color="#D0D0D0"/>
<stop offset="0.06" stop-color="#606060"/>
<stop offset="0.94" stop-color="#606060"/>
<stop offset="0.97" stop-color="#D0D0D0"/>
<stop offset="1" stop-color="#404040"/>
</linearGradient>
<linearGradient id="paint1_linear_293_18" x1="116" y1="112" x2="12" y2="112" gradientUnits="userSpaceOnUse">
<stop stop-color="#404040"/>
<stop offset="0.03" stop-color="#D0D0D0"/>
<stop offset="0.06" stop-color="#606060"/>
<stop offset="0.94" stop-color="#606060"/>
<stop offset="0.97" stop-color="#D0D0D0"/>
<stop offset="1" stop-color="#404040"/>
</linearGradient>
<linearGradient id="paint2_linear_293_18" x1="24" y1="85.8476" x2="103.999" y2="85.6325" gradientUnits="userSpaceOnUse">
<stop stop-color="#AFAFAF"/>
<stop offset="0.04" stop-color="#F6F5F4"/>
<stop offset="0.08" stop-color="#D0D0D0"/>
<stop offset="0.92" stop-color="#D0D0D0"/>
<stop offset="0.96" stop-color="#F6F5F4"/>
<stop offset="1" stop-color="#AFAFAF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -1,5 +1,5 @@
project('yafi', project('yafi',
version: '0.1.0', version: '1.0',
meson_version: '>= 1.0.0', meson_version: '>= 1.0.0',
default_options: [ 'warning_level=2', 'werror=false', ], default_options: [ 'warning_level=2', 'werror=false', ],
) )

Binary file not shown.

BIN
pyinstaller/splash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

301
pyinstaller/splash.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 48 KiB

BIN
pyinstaller/yafi.ico Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 398 KiB

View File

@@ -1,11 +1,15 @@
# -*- mode: python ; coding: utf-8 -*- # -*- mode: python ; coding: utf-8 -*-
from PyInstaller.utils.hooks import collect_data_files from PyInstaller.utils.hooks import collect_data_files
import os import os
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--onefile", action="store_true")
options = parser.parse_args()
datas = [('LpcCrOSEC.bin', '.')] if os.name == 'nt' and os.path.exists('LpcCrOSEC.bin') else [] datas = [('LpcCrOSEC.bin', '.')] if os.name == 'nt' and os.path.exists('LpcCrOSEC.bin') else []
datas += collect_data_files('yafi') datas += collect_data_files('yafi')
a = Analysis( a = Analysis(
['entrypoint.py'], ['entrypoint.py'],
pathex=[], pathex=[],
@@ -21,12 +25,34 @@ a = Analysis(
) )
pyz = PYZ(a.pure) pyz = PYZ(a.pure)
if options.onefile:
splash = Splash(
'splash.png',
binaries=a.binaries,
datas=a.datas,
text_pos=(4, 480),
# Text doesn't scale on Linux, but does on Windows
text_size=12 if os.name == 'nt' else 6,
minify_script=True,
always_on_top=True,
)
exe_args = (
[
a.scripts,
a.binaries,
a.datas,
splash,
splash.binaries,
]
if options.onefile
else [a.scripts]
)
exe = EXE( exe = EXE(
pyz, pyz,
a.scripts, *exe_args,
a.binaries, exclude_binaries=not options.onefile,
a.datas,
[],
name='YAFI', name='YAFI',
debug=False, debug=False,
bootloader_ignore_signals=False, bootloader_ignore_signals=False,
@@ -42,3 +68,14 @@ exe = EXE(
entitlements_file=None, entitlements_file=None,
icon=['yafi.ico'], icon=['yafi.ico'],
) )
if not options.onefile:
coll = COLLECT(
exe,
a.binaries,
a.datas,
strip=False,
upx=True,
upx_exclude=[],
name='YAFI',
)

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "yafi" name = "yafi"
version = "0.5" version = "1.0"
authors = [ authors = [
{ name="Steve-Tech" } { name="Steve-Tech" }
] ]
@@ -8,11 +8,10 @@ description = "Yet Another Framework Interface"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"
dependencies = [ dependencies = [
"cros_ec_python >= 0.2.0", "cros_ec_python >= 0.4.0",
"PyGObject" "PyGObject"
] ]
classifiers = [ classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: End Users/Desktop", "Intended Audience :: End Users/Desktop",
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
"Operating System :: POSIX :: Linux", "Operating System :: POSIX :: Linux",

View File

@@ -0,0 +1,14 @@
{
"name": "python3-cros_ec_python",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"cros_ec_python\" --no-build-isolation"
],
"sources": [
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/6c/7a/10d978a02bbe37530490cfd14e0994c433dc29c81b3afcdbde453d512528/cros_ec_python-0.3.0-py3-none-any.whl",
"sha256": "aeb14ebdbd60ec6d6a4b11df1482a295466da4a908a468d168efd4cc141e7e3d"
}
]
}

View File

@@ -18,9 +18,7 @@
# #
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
from gi.repository import Adw from gi.repository import Gtk, Adw, GLib
from gi.repository import Gtk
from gi.repository import GLib
import cros_ec_python.commands as ec_commands import cros_ec_python.commands as ec_commands
import cros_ec_python.exceptions as ec_exceptions import cros_ec_python.exceptions as ec_exceptions
@@ -52,6 +50,9 @@ class BatteryPage(Gtk.Box):
def setup(self, app): def setup(self, app):
battery = ec_commands.memmap.get_battery_values(app.cros_ec) battery = ec_commands.memmap.get_battery_values(app.cros_ec)
if not battery:
self.batt_status.set_subtitle("No data")
return
self.batt_manu.set_subtitle(battery["manufacturer"]) self.batt_manu.set_subtitle(battery["manufacturer"])
self.batt_model.set_subtitle(battery["model"]) self.batt_model.set_subtitle(battery["model"])
self.batt_serial.set_subtitle(battery["serial"]) self.batt_serial.set_subtitle(battery["serial"])

View File

@@ -18,9 +18,7 @@
# #
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
from gi.repository import Adw from gi.repository import Gtk, Adw, GLib
from gi.repository import Gtk
from gi.repository import GLib
import cros_ec_python.commands as ec_commands import cros_ec_python.commands as ec_commands
import cros_ec_python.exceptions as ec_exceptions import cros_ec_python.exceptions as ec_exceptions
@@ -36,8 +34,6 @@ class BatteryLimiterPage(Gtk.Box):
bat_limit = Gtk.Template.Child() bat_limit = Gtk.Template.Child()
bat_limit_label = Gtk.Template.Child() bat_limit_label = Gtk.Template.Child()
bat_limit_scale = Gtk.Template.Child() bat_limit_scale = Gtk.Template.Child()
chg_limit_override = Gtk.Template.Child()
chg_limit_override_btn = Gtk.Template.Child()
bat_ext_group = Gtk.Template.Child() bat_ext_group = Gtk.Template.Child()
bat_ext_enable = Gtk.Template.Child() bat_ext_enable = Gtk.Template.Child()
@@ -63,7 +59,6 @@ class BatteryLimiterPage(Gtk.Box):
self.bat_limit_label.set_label(f"{ec_limit[1]}%") self.bat_limit_label.set_label(f"{ec_limit[1]}%")
self.chg_limit.set_sensitive(True) self.chg_limit.set_sensitive(True)
self.bat_limit.set_sensitive(True) self.bat_limit.set_sensitive(True)
self.chg_limit_override.set_sensitive(True)
def handle_chg_limit_change(min, max): def handle_chg_limit_change(min, max):
ec_commands.framework_laptop.set_charge_limit( ec_commands.framework_laptop.set_charge_limit(
@@ -81,7 +76,6 @@ class BatteryLimiterPage(Gtk.Box):
self.chg_limit.set_sensitive(active) self.chg_limit.set_sensitive(active)
self.bat_limit.set_sensitive(active) self.bat_limit.set_sensitive(active)
self.chg_limit_override.set_sensitive(active)
self.chg_limit_enable.connect( self.chg_limit_enable.connect(
"notify::active", lambda switch, _: handle_chg_limit_enable(switch) "notify::active", lambda switch, _: handle_chg_limit_enable(switch)
@@ -99,12 +93,6 @@ class BatteryLimiterPage(Gtk.Box):
), ),
) )
self.chg_limit_override_btn.connect(
"clicked",
lambda _: ec_commands.framework_laptop.override_charge_limit(
app.cros_ec
),
)
except ec_exceptions.ECError as e: except ec_exceptions.ECError as e:
if e.ec_status == ec_exceptions.EcStatus.EC_RES_INVALID_COMMAND: if e.ec_status == ec_exceptions.EcStatus.EC_RES_INVALID_COMMAND:
app.no_support.append(ec_commands.framework_laptop.EC_CMD_CHARGE_LIMIT_CONTROL) app.no_support.append(ec_commands.framework_laptop.EC_CMD_CHARGE_LIMIT_CONTROL)

View File

@@ -18,9 +18,7 @@
# #
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
from gi.repository import Adw from gi.repository import Gtk, Adw, GLib
from gi.repository import Gtk
from gi.repository import GLib
import cros_ec_python.commands as ec_commands import cros_ec_python.commands as ec_commands
import cros_ec_python.exceptions as ec_exceptions import cros_ec_python.exceptions as ec_exceptions
@@ -29,17 +27,24 @@ import cros_ec_python.exceptions as ec_exceptions
class HardwarePage(Gtk.Box): class HardwarePage(Gtk.Box):
__gtype_name__ = 'HardwarePage' __gtype_name__ = 'HardwarePage'
hw_als = Gtk.Template.Child()
hw_als_label = Gtk.Template.Child()
hw_chassis = Gtk.Template.Child() hw_chassis = Gtk.Template.Child()
hw_chassis_label = Gtk.Template.Child() hw_chassis_label = Gtk.Template.Child()
hw_fp_pwr = Gtk.Template.Child()
hw_fp_pwr_en = Gtk.Template.Child()
hw_fp_pwr_dis = Gtk.Template.Child()
hw_priv_cam = Gtk.Template.Child() hw_priv_cam = Gtk.Template.Child()
hw_priv_cam_sw = Gtk.Template.Child() hw_priv_cam_sw = Gtk.Template.Child()
hw_priv_mic = Gtk.Template.Child() hw_priv_mic = Gtk.Template.Child()
hw_priv_mic_sw = Gtk.Template.Child() hw_priv_mic_sw = Gtk.Template.Child()
hw_lid_open = Gtk.Template.Child()
hw_fp_pwr = Gtk.Template.Child() hw_lid_open_sw = Gtk.Template.Child()
hw_fp_pwr_en = Gtk.Template.Child() hw_pwr_btn = Gtk.Template.Child()
hw_fp_pwr_dis = Gtk.Template.Child() hw_pwr_btn_sw = Gtk.Template.Child()
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
@@ -68,7 +73,13 @@ class HardwarePage(Gtk.Box):
GLib.timeout_add_seconds(1, self._update_hardware, app) GLib.timeout_add_seconds(1, self._update_hardware, app)
def _update_hardware(self, app): def _update_hardware(self, app):
success = False # Memmap (ALS and Lid Open)
als = ec_commands.memmap.get_als(app.cros_ec)
self.hw_als_label.set_label(f"{als[0]} lux" if als[0] != 65535 else "MAX")
switches = ec_commands.memmap.get_switches(app.cros_ec)
self.hw_lid_open_sw.set_active(switches["lid_open"])
self.hw_pwr_btn_sw.set_active(switches["power_button_pressed"])
# Chassis # Chassis
if not ec_commands.framework_laptop.EC_CMD_CHASSIS_INTRUSION in app.no_support: if not ec_commands.framework_laptop.EC_CMD_CHASSIS_INTRUSION in app.no_support:
try: try:
@@ -84,8 +95,6 @@ class HardwarePage(Gtk.Box):
self.hw_chassis.set_subtitle( self.hw_chassis.set_subtitle(
"Currently " + ("Open" if ec_chassis_open else "Closed") "Currently " + ("Open" if ec_chassis_open else "Closed")
) )
success = True
except ec_exceptions.ECError as e: except ec_exceptions.ECError as e:
if e.ec_status == ec_exceptions.EcStatus.EC_RES_INVALID_COMMAND: if e.ec_status == ec_exceptions.EcStatus.EC_RES_INVALID_COMMAND:
app.no_support.append( app.no_support.append(
@@ -106,8 +115,6 @@ class HardwarePage(Gtk.Box):
) )
self.hw_priv_cam_sw.set_active(ec_privacy["camera"]) self.hw_priv_cam_sw.set_active(ec_privacy["camera"])
self.hw_priv_mic_sw.set_active(ec_privacy["microphone"]) self.hw_priv_mic_sw.set_active(ec_privacy["microphone"])
success = True
except ec_exceptions.ECError as e: except ec_exceptions.ECError as e:
if e.ec_status == ec_exceptions.EcStatus.EC_RES_INVALID_COMMAND: if e.ec_status == ec_exceptions.EcStatus.EC_RES_INVALID_COMMAND:
app.no_support.append( app.no_support.append(
@@ -118,4 +125,4 @@ class HardwarePage(Gtk.Box):
else: else:
raise e raise e
return app.current_page == 4 and success return app.current_page == 4

View File

@@ -18,8 +18,7 @@
# #
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
from gi.repository import Adw from gi.repository import Gtk, Adw, GLib
from gi.repository import Gtk
import cros_ec_python.commands as ec_commands import cros_ec_python.commands as ec_commands
import cros_ec_python.exceptions as ec_exceptions import cros_ec_python.exceptions as ec_exceptions
@@ -28,6 +27,8 @@ import cros_ec_python.exceptions as ec_exceptions
class LedsPage(Gtk.Box): class LedsPage(Gtk.Box):
__gtype_name__ = 'LedsPage' __gtype_name__ = 'LedsPage'
first_run = True
led_pwr = Gtk.Template.Child() led_pwr = Gtk.Template.Child()
led_pwr_scale = Gtk.Template.Child() led_pwr_scale = Gtk.Template.Child()
@@ -36,27 +37,30 @@ class LedsPage(Gtk.Box):
led_advanced = Gtk.Template.Child() led_advanced = Gtk.Template.Child()
led_pwr_colour = Gtk.Template.Child()
led_chg_colour = Gtk.Template.Child()
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
def setup(self, app): def setup(self, app):
# Power LED # Power LED
try: try:
def handle_led_pwr(scale): def handle_led_pwr(scale):
value = int(abs(scale.get_value() - 2)) value = int(abs(scale.get_value() - 2))
ec_commands.framework_laptop.set_fp_led_level(app.cros_ec, value) ec_commands.framework_laptop.set_fp_led_level(app.cros_ec, value)
self.led_pwr.set_subtitle(["High", "Medium", "Low"][value]) self.led_pwr.set_subtitle(["High", "Medium", "Low"][value])
current_fp_level = ec_commands.framework_laptop.get_fp_led_level( try:
app.cros_ec current_fp_level = ec_commands.framework_laptop.get_fp_led_level(
).value app.cros_ec
self.led_pwr_scale.set_value(abs(current_fp_level - 2)) ).value
self.led_pwr.set_subtitle(["High", "Medium", "Low"][current_fp_level]) self.led_pwr_scale.set_value(abs(current_fp_level - 2))
self.led_pwr.set_subtitle(["High", "Medium", "Low"][current_fp_level])
except ValueError:
# LED isn't a normal value
current_fp_level = ec_commands.framework_laptop.get_fp_led_level_int(
app.cros_ec
)
self.led_pwr.set_subtitle(f"Custom ({current_fp_level}%)")
self.led_pwr_scale.connect("value-changed", handle_led_pwr) self.led_pwr_scale.connect("value-changed", handle_led_pwr)
except ec_exceptions.ECError as e: except ec_exceptions.ECError as e:
if e.ec_status == ec_exceptions.EcStatus.EC_RES_INVALID_COMMAND: if e.ec_status == ec_exceptions.EcStatus.EC_RES_INVALID_COMMAND:
@@ -85,31 +89,38 @@ class LedsPage(Gtk.Box):
self.led_kbd.set_visible(False) self.led_kbd.set_visible(False)
# Advanced options # Advanced options
if ec_commands.general.get_cmd_versions( if (
app.cros_ec, ec_commands.leds.EC_CMD_LED_CONTROL ec_commands.general.get_cmd_versions(
app.cros_ec, ec_commands.leds.EC_CMD_LED_CONTROL
)
and self.first_run
): ):
# Advanced: Power LED
led_pwr_colour_strings = self.led_pwr_colour.get_model()
all_colours = ["Red", "Green", "Blue", "Yellow", "White", "Amber"] all_colours = ["Red", "Green", "Blue", "Yellow", "White", "Amber"]
led_names = {
def add_colours(strings, led_id): ec_commands.leds.EcLedId.EC_LED_ID_BATTERY_LED: "Battery LED",
# Auto and Off should already be present ec_commands.leds.EcLedId.EC_LED_ID_POWER_LED: "Power LED",
if strings.get_n_items() <= 2: ec_commands.leds.EcLedId.EC_LED_ID_ADAPTER_LED: "Adapter LED",
supported_colours = ec_commands.leds.led_control_get_max_values( ec_commands.leds.EcLedId.EC_LED_ID_LEFT_LED: "Left LED",
ec_commands.leds.EcLedId.EC_LED_ID_RIGHT_LED: "Right LED",
ec_commands.leds.EcLedId.EC_LED_ID_RECOVERY_HW_REINIT_LED: "Recovery LED",
ec_commands.leds.EcLedId.EC_LED_ID_SYSRQ_DEBUG_LED: "SysRq LED",
}
leds = {}
for i in range(ec_commands.leds.EcLedId.EC_LED_ID_COUNT.value):
try:
led_id = ec_commands.leds.EcLedId(i)
leds[led_id] = ec_commands.leds.led_control_get_max_values(
app.cros_ec, led_id app.cros_ec, led_id
) )
for i, colour in enumerate(all_colours): except ec_exceptions.ECError as e:
if supported_colours[i]: if e.ec_status == ec_exceptions.EcStatus.EC_RES_INVALID_PARAM:
strings.append(colour) continue
else:
try: raise e
add_colours(
led_pwr_colour_strings, ec_commands.leds.EcLedId.EC_LED_ID_POWER_LED # Power LED does not support Blue, even though Intel models think they do
) leds[ec_commands.leds.EcLedId.EC_LED_ID_POWER_LED][2] = 0
except ec_exceptions.ECError as e:
self.led_pwr_colour.set_sensitive(False)
def handle_led_colour(combobox, led_id): def handle_led_colour(combobox, led_id):
colour = combobox.get_selected() - 2 colour = combobox.get_selected() - 2
@@ -133,30 +144,20 @@ class LedsPage(Gtk.Box):
100, 100,
ec_commands.leds.EcLedColors(colour_idx), ec_commands.leds.EcLedColors(colour_idx),
) )
for led_id, supported_colours in leds.items():
if any(supported_colours):
combo = Adw.ComboRow(title=led_names[led_id])
model = Gtk.StringList.new(["Auto", "Off"])
for i, colour in enumerate(all_colours):
if supported_colours[i]:
model.append(colour)
combo.set_model(model)
combo.connect(
"notify::selected",
lambda combobox, _, led_id=led_id: handle_led_colour(
combobox, led_id
),
)
self.led_advanced.add_row(combo)
self.led_pwr_colour.connect( self.first_run = False
"notify::selected",
lambda combo, _: handle_led_colour(
combo, ec_commands.leds.EcLedId.EC_LED_ID_POWER_LED
),
)
# Advanced: Charging LED
led_chg_colour_strings = self.led_chg_colour.get_model()
try:
add_colours(
led_chg_colour_strings,
ec_commands.leds.EcLedId.EC_LED_ID_BATTERY_LED,
)
except ec_exceptions.ECError as e:
self.led_chg_colour.set_sensitive(False)
self.led_chg_colour.connect(
"notify::selected",
lambda combo, _: handle_led_colour(
combo, ec_commands.leds.EcLedId.EC_LED_ID_BATTERY_LED
),
)
else:
self.led_advanced.set_visible(False)

View File

@@ -18,15 +18,16 @@
# #
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
import os
import sys import sys
import traceback import traceback
import threading
import gi import gi
from gi.repository import Gio
gi.require_version('Gtk', '4.0') gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1') gi.require_version('Adw', '1')
from gi.repository import Gtk, Gio, Adw from gi.repository import Gtk, Gio, Adw, GLib
from .window import YafiWindow from .window import YafiWindow
from .thermals import ThermalsPage from .thermals import ThermalsPage
from .leds import LedsPage from .leds import LedsPage
@@ -66,6 +67,12 @@ class YafiApplication(Adw.Application):
if not self.win: if not self.win:
self.win = YafiWindow(application=self) self.win = YafiWindow(application=self)
# Update the splash screen
splash = getattr(sys, 'frozen', False) and '_PYI_SPLASH_IPC' in os.environ
if splash:
import pyi_splash
pyi_splash.update_text("Detecting EC")
try: try:
self.cros_ec = get_cros_ec() self.cros_ec = get_cros_ec()
pass pass
@@ -81,9 +88,16 @@ class YafiApplication(Adw.Application):
+ "If you are using a Framework Laptop, there are additional troubleshooting steps in the README." + "If you are using a Framework Laptop, there are additional troubleshooting steps in the README."
) )
self.show_error("EC Initalisation Error", message) self.show_error("EC Initalisation Error", message)
if splash:
pyi_splash.close()
self.win.present() self.win.present()
return return
if splash:
pyi_splash.update_text("Building Interface")
self.change_page(self.win.content, ThermalsPage()) self.change_page(self.win.content, ThermalsPage())
pages = ( pages = (
@@ -91,7 +105,7 @@ class YafiApplication(Adw.Application):
("LEDs", LedsPage()), ("LEDs", LedsPage()),
("Battery", BatteryPage()), ("Battery", BatteryPage()),
("Battery Limiter", BatteryLimiterPage()), ("Battery Limiter", BatteryLimiterPage()),
("Hardware", HardwarePage()), ("Sensors", HardwarePage()),
("About", None), ("About", None),
) )
@@ -107,10 +121,14 @@ class YafiApplication(Adw.Application):
self.current_page = page self.current_page = page
self.change_page(self.win.content, pages[page][1]) self.change_page(self.win.content, pages[page][1])
else: else:
self.win.navbar.select_row(self.win.navbar.get_row_at_index(self.current_page))
self.on_about_action() self.on_about_action()
self.win.navbar.connect("row-activated", lambda box, row: switch_page(row.get_index())) self.win.navbar.connect("row-activated", lambda box, row: switch_page(row.get_index()))
if splash:
pyi_splash.close()
self.win.present() self.win.present()
def on_about_action(self, *args): def on_about_action(self, *args):
@@ -118,20 +136,26 @@ class YafiApplication(Adw.Application):
about = Adw.AboutDialog( about = Adw.AboutDialog(
application_icon="au.stevetech.yafi", application_icon="au.stevetech.yafi",
application_name="Yet Another Framework Interface", application_name="Yet Another Framework Interface",
comments="YAFI is another GUI for the Framework Laptop Embedded Controller.\n" comments="YAFI is another GUI for the Framework Laptop Embedded Controller.\n\n"
+ "It is written in Python with a GTK3 theme, and uses the `CrOS_EC_Python` library to communicate with the EC.", + "It is written in Python with a GTK4 Adwaita theme, and uses the CrOS_EC_Python library to communicate with the EC.\n\n"
copyright="© 2025 Stephen Horvath", + "YAFI is not affiliated with Framework Computer Inc. in any way.",
debug_info=self.generate_debug_info(), copyright="© 2026 Stephen Horvath",
developer_name="Stephen Horvath", developer_name="Stephen Horvath",
developers=["Stephen Horvath"], developers=["Stephen Horvath https://github.com/Steve-Tech"],
artists=["Mirabelle SALLES https://github.com/oiimrosabel"],
issue_url="https://github.com/Steve-Tech/YAFI/issues", issue_url="https://github.com/Steve-Tech/YAFI/issues",
license_type=Gtk.License.GPL_2_0, license_type=Gtk.License.GPL_2_0,
version="0.5", version="1.0",
website="https://github.com/Steve-Tech/YAFI", website="https://github.com/Steve-Tech/YAFI",
) )
about.add_acknowledgement_section(None, ["Framework Computer Inc. https://frame.work/"]) about.add_acknowledgement_section(None, ["Framework Computer Inc. https://frame.work/"])
about.present(self.props.active_window) about.present(self.props.active_window)
if hasattr(self, 'debug_info'):
about.set_debug_info(self.debug_info)
else:
threading.Thread(target=lambda: GLib.idle_add(about.set_debug_info, self.generate_debug_info())).start()
def show_error(self, heading, message): def show_error(self, heading, message):
dialog = Adw.AlertDialog(heading=heading, body=message) dialog = Adw.AlertDialog(heading=heading, body=message)
dialog.add_response("exit", "Exit") dialog.add_response("exit", "Exit")
@@ -179,6 +203,8 @@ class YafiApplication(Adw.Application):
info += f"Model: {f.read().strip()}\n" info += f"Model: {f.read().strip()}\n"
with open('/sys/devices/virtual/dmi/id/product_sku', 'r') as f: with open('/sys/devices/virtual/dmi/id/product_sku', 'r') as f:
info += f"SKU: {f.read().strip()}\n" info += f"SKU: {f.read().strip()}\n"
with open('/sys/devices/virtual/dmi/id/board_name', 'r') as f:
info += f"Board: {f.read().strip()}\n"
with open('/sys/devices/virtual/dmi/id/bios_vendor', 'r') as f: with open('/sys/devices/virtual/dmi/id/bios_vendor', 'r') as f:
info += f"BIOS Vendor: {f.read().strip()}\n" info += f"BIOS Vendor: {f.read().strip()}\n"
with open('/sys/devices/virtual/dmi/id/bios_version', 'r') as f: with open('/sys/devices/virtual/dmi/id/bios_version', 'r') as f:
@@ -190,10 +216,12 @@ class YafiApplication(Adw.Application):
ps_cmd = ( ps_cmd = (
"powershell -Command " "powershell -Command "
"\"$cs = Get-CimInstance -ClassName Win32_ComputerSystem; " "\"$cs = Get-CimInstance -ClassName Win32_ComputerSystem; "
"$board = Get-CimInstance -ClassName Win32_BaseBoard; "
"$bios = Get-CimInstance -ClassName Win32_BIOS; " "$bios = Get-CimInstance -ClassName Win32_BIOS; "
"Write-Output $cs.Manufacturer; " "Write-Output $cs.Manufacturer; "
"Write-Output $cs.Model; " "Write-Output $cs.Model; "
"Write-Output $cs.SystemSKUNumber; " "Write-Output $cs.SystemSKUNumber; "
"Write-Output $board.Product; "
"Write-Output $bios.Manufacturer; " "Write-Output $bios.Manufacturer; "
"Write-Output $bios.Name; " "Write-Output $bios.Name; "
"Write-Output $bios.ReleaseDate\"" "Write-Output $bios.ReleaseDate\""
@@ -202,10 +230,11 @@ class YafiApplication(Adw.Application):
info += f"Manufacturer: {output[0]}\n" info += f"Manufacturer: {output[0]}\n"
info += f"Model: {output[1]}\n" info += f"Model: {output[1]}\n"
info += f"SKU: {output[2]}\n" info += f"SKU: {output[2]}\n"
info += f"BIOS Vendor: {output[3]}\n" info += f"Board: {output[3]}\n"
info += f"BIOS Version: {output[4]}\n" info += f"BIOS Vendor: {output[4]}\n"
info += f"BIOS Version: {output[5]}\n"
# Blank line in the output for some reason # Blank line in the output for some reason
info += f"BIOS Date: {output[6]}\n" info += f"BIOS Date: {output[7]}\n"
except Exception as e: except Exception as e:
info += f"System Info Error: {type(e).__name__}: {e}\n" info += f"System Info Error: {type(e).__name__}: {e}\n"

View File

@@ -18,9 +18,7 @@
# #
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
from gi.repository import Adw from gi.repository import Gtk, Adw, GLib
from gi.repository import Gtk
from gi.repository import GLib
import cros_ec_python.commands as ec_commands import cros_ec_python.commands as ec_commands
import cros_ec_python.exceptions as ec_exceptions import cros_ec_python.exceptions as ec_exceptions
@@ -29,11 +27,17 @@ import cros_ec_python.exceptions as ec_exceptions
class ThermalsPage(Gtk.Box): class ThermalsPage(Gtk.Box):
__gtype_name__ = 'ThermalsPage' __gtype_name__ = 'ThermalsPage'
first_run = True
fan_rpm = Gtk.Template.Child() fan_rpm = Gtk.Template.Child()
fan_mode = Gtk.Template.Child() fan_mode = Gtk.Template.Child()
fan_set_rpm = Gtk.Template.Child() fan_set_rpm = Gtk.Template.Child()
fan_set_percent = Gtk.Template.Child() fan_set_percent = Gtk.Template.Child()
fan_percent_scale = Gtk.Template.Child() fan_percent_scale = Gtk.Template.Child()
fan_set_points = Gtk.Template.Child()
set_points = []
ec_set_points_supported = False
ec_set_points = []
temperatures = Gtk.Template.Child() temperatures = Gtk.Template.Child()
temp_items = [] temp_items = []
@@ -42,10 +46,40 @@ class ThermalsPage(Gtk.Box):
super().__init__(**kwargs) super().__init__(**kwargs)
def setup(self, app): def setup(self, app):
# Temperature sensors
while temp_child := self.temperatures.get_last_child():
self.temperatures.remove(temp_child)
self.temp_items.clear()
try:
ec_temp_sensors = ec_commands.thermal.get_temp_sensors(app.cros_ec)
except ec_exceptions.ECError as e:
if e.ec_status == ec_exceptions.EcStatus.EC_RES_INVALID_COMMAND:
# Generate some labels if the command is not supported
ec_temp_sensors = {}
temps = ec_commands.memmap.get_temps(app.cros_ec)
for i, temp in enumerate(temps):
ec_temp_sensors[f"Sensor {i}"] = (temp, None)
else:
raise e
for key, value in ec_temp_sensors.items():
off_row = Adw.ActionRow(title=key, subtitle=f"{value[0]}°C" if value[0] is not None else "Error")
off_row.add_css_class("property")
self.temperatures.append(off_row)
self.temp_items.append(off_row)
self._update_thermals(app)
# Don't let the user change the fans if they can't get back to auto # Don't let the user change the fans if they can't get back to auto
if ec_commands.general.get_cmd_versions( if ec_commands.general.get_cmd_versions(
app.cros_ec, ec_commands.thermal.EC_CMD_THERMAL_AUTO_FAN_CTRL app.cros_ec, ec_commands.thermal.EC_CMD_THERMAL_AUTO_FAN_CTRL
): ):
self.ec_set_points_supported = ec_commands.general.check_cmd_version(
app.cros_ec, ec_commands.thermal.EC_CMD_THERMAL_GET_THRESHOLD, 1
) and ec_commands.general.check_cmd_version(
app.cros_ec, ec_commands.thermal.EC_CMD_THERMAL_SET_THRESHOLD, 1
)
def handle_fan_mode(mode): def handle_fan_mode(mode):
match mode: match mode:
@@ -53,13 +87,18 @@ class ThermalsPage(Gtk.Box):
self.fan_set_rpm.set_visible(False) self.fan_set_rpm.set_visible(False)
self.fan_set_percent.set_visible(False) self.fan_set_percent.set_visible(False)
ec_commands.thermal.thermal_auto_fan_ctrl(app.cros_ec) ec_commands.thermal.thermal_auto_fan_ctrl(app.cros_ec)
self.fan_set_points.set_visible(self.ec_set_points_supported)
case 1: # Percent case 1: # Percent
self.fan_set_points.set_visible(False)
self.fan_set_rpm.set_visible(False) self.fan_set_rpm.set_visible(False)
self.fan_set_percent.set_visible(True) self.fan_set_percent.set_visible(True)
case 2: # RPM case 2: # RPM
self.fan_set_points.set_visible(False)
self.fan_set_rpm.set_visible(True) self.fan_set_rpm.set_visible(True)
self.fan_set_percent.set_visible(False) self.fan_set_percent.set_visible(False)
handle_fan_mode(self.fan_mode.get_selected())
self.fan_mode.connect( self.fan_mode.connect(
"notify::selected", "notify::selected",
lambda combo, _: handle_fan_mode(combo.get_selected()), lambda combo, _: handle_fan_mode(combo.get_selected()),
@@ -83,41 +122,77 @@ class ThermalsPage(Gtk.Box):
): ):
def handle_fan_rpm(entry): def handle_fan_rpm(entry):
rpm = int(entry.get_text()) rpm = int(entry.get_value())
ec_commands.pwm.pwm_set_fan_rpm(app.cros_ec, rpm) ec_commands.pwm.pwm_set_fan_rpm(app.cros_ec, rpm)
self.fan_set_rpm.connect( self.fan_set_rpm.connect(
"notify::text", lambda entry, _: handle_fan_rpm(entry) "notify::value", lambda entry, _: handle_fan_rpm(entry)
) )
else: else:
self.fan_set_rpm.set_sensitive(False) self.fan_set_rpm.set_sensitive(False)
else: else:
self.fan_mode.set_sensitive(False) self.fan_mode.set_sensitive(False)
# Temperature sensors # Set points
while temp_child := self.temperatures.get_last_child(): if self.ec_set_points_supported and self.first_run:
self.temperatures.remove(temp_child) def handle_set_point(entry, key):
self.temp_items.clear() index = entry.ec_index
temp = int(entry.get_value())
# Don't allow an off temp higher than max temp and vice versa
match key:
case "temp_fan_off":
if temp > self.ec_set_points[index]["temp_fan_max"]:
entry.set_value(self.ec_set_points[index]["temp_fan_off"])
return
case "temp_fan_max":
if temp < self.ec_set_points[index]["temp_fan_off"]:
entry.set_value(self.ec_set_points[index]["temp_fan_max"])
return
self.ec_set_points[entry.ec_index][key] = temp
ec_commands.thermal.thermal_set_thresholds(
app.cros_ec, index,
self.ec_set_points[index]
)
try: for i, sensor in enumerate(ec_temp_sensors):
ec_temp_sensors = ec_commands.thermal.get_temp_sensors(app.cros_ec) ec_set_point = ec_commands.thermal.thermal_get_thresholds(app.cros_ec, i)
except ec_exceptions.ECError as e: self.ec_set_points.append(ec_set_point)
if e.ec_status == ec_exceptions.EcStatus.EC_RES_INVALID_COMMAND: off_row = Adw.SpinRow(
# Generate some labels if the command is not supported title=f"Fan On - {sensor}",
ec_temp_sensors = {} subtitle=f"Turn fan on when above temp (°C)",
temps = ec_commands.memmap.get_temps(app.cros_ec) )
for i, temp in enumerate(temps): off_row.ec_index = i
ec_temp_sensors[f"Sensor {i}"] = (temp, None) # 0K to 65535K for 16bit unsigned range
else: # Actually the EC takes 32bits, but let's keep it like this for sanity
raise e off_row.set_adjustment(Gtk.Adjustment(
lower=-273,
upper=65_262,
page_increment=10,
step_increment=1,
value=ec_set_point["temp_fan_off"],
))
off_row.connect(
"notify::value", lambda entry, _: handle_set_point(entry, "temp_fan_off")
)
max_row = Adw.SpinRow(
title=f"Fan Max - {sensor}",
subtitle=f"Max fan speed when above temp (°C)",
)
max_row.ec_index = i
max_row.set_adjustment(Gtk.Adjustment(
lower=-273,
upper=65_262,
page_increment=10,
step_increment=1,
value=ec_set_point["temp_fan_max"],
))
max_row.connect(
"notify::value", lambda entry, _: handle_set_point(entry, "temp_fan_max")
)
self.fan_set_points.add_row(off_row)
self.fan_set_points.add_row(max_row)
for key, value in ec_temp_sensors.items(): self.first_run = False
new_row = Adw.ActionRow(title=key, subtitle=f"{value[0]}°C")
new_row.add_css_class("property")
self.temperatures.append(new_row)
self.temp_items.append(new_row)
self._update_thermals(app)
# Schedule _update_thermals to run every second # Schedule _update_thermals to run every second
GLib.timeout_add_seconds(1, self._update_thermals, app) GLib.timeout_add_seconds(1, self._update_thermals, app)
@@ -130,7 +205,7 @@ class ThermalsPage(Gtk.Box):
ec_temp_sensors = ec_commands.memmap.get_temps(app.cros_ec) ec_temp_sensors = ec_commands.memmap.get_temps(app.cros_ec)
# The temp sensors disappear sometimes, so we need to handle that # The temp sensors disappear sometimes, so we need to handle that
for i in range(min(len(self.temp_items), len(ec_temp_sensors))): for i in range(min(len(self.temp_items), len(ec_temp_sensors))):
self.temp_items[i].set_subtitle(f"{ec_temp_sensors[i]}°C") self.temp_items[i].set_subtitle(f"{ec_temp_sensors[i]}°C" if ec_temp_sensors[i] is not None else "Error")
# Check if this has already failed and skip if it has # Check if this has already failed and skip if it has
if not ec_commands.pwm.EC_CMD_PWM_GET_FAN_TARGET_RPM in app.no_support: if not ec_commands.pwm.EC_CMD_PWM_GET_FAN_TARGET_RPM in app.no_support:

View File

@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.96.1 --> <!-- Created with Cambalache 0.96.3 -->
<interface> <interface>
<!-- interface-name battery-limiter.ui --> <!-- interface-name battery-limiter.ui -->
<!-- interface-description The Battery page for YAFI --> <!-- interface-description The Battery page for YAFI -->
@@ -79,25 +79,6 @@
</child> </child>
</object> </object>
</child> </child>
<child>
<object class="AdwActionRow" id="chg_limit_override">
<property name="sensitive">False</property>
<property name="subtitle">Disables the limiter for one charge</property>
<property name="title">Override Charge Limiter</property>
<child>
<object class="GtkBox">
<property name="halign">end</property>
<property name="homogeneous">True</property>
<property name="valign">center</property>
<child>
<object class="GtkButton" id="chg_limit_override_btn">
<property name="label">Override</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child> <child>
<object class="AdwPreferencesGroup" id="bat_ext_group"> <object class="AdwPreferencesGroup" id="bat_ext_group">
<property name="description">Preserve the battery lifespan by gradually lowering battery charge voltage automatically if the system is connected to AC for more than the set day limit.</property> <property name="description">Preserve the battery lifespan by gradually lowering battery charge voltage automatically if the system is connected to AC for more than the set day limit.</property>

View File

@@ -2,7 +2,7 @@
<!-- Created with Cambalache 0.96.1 --> <!-- Created with Cambalache 0.96.1 -->
<interface> <interface>
<!-- interface-name hardware.ui --> <!-- interface-name hardware.ui -->
<!-- interface-description The Hardware page for YAFI --> <!-- interface-description The Sensors page for YAFI -->
<!-- interface-copyright Steve-Tech --> <!-- interface-copyright Steve-Tech -->
<requires lib="gtk" version="4.0"/> <requires lib="gtk" version="4.0"/>
<requires lib="libadwaita" version="1.0"/> <requires lib="libadwaita" version="1.0"/>
@@ -15,7 +15,15 @@
<child> <child>
<object class="AdwActionRow"> <object class="AdwActionRow">
<property name="selectable">False</property> <property name="selectable">False</property>
<property name="title">Hardware Status</property> <property name="title">Sensors</property>
</object>
</child>
<child>
<object class="AdwActionRow" id="hw_als">
<property name="title">Ambient Light Sensor</property>
<child>
<object class="GtkLabel" id="hw_als_label"/>
</child>
</object> </object>
</child> </child>
<child> <child>
@@ -26,6 +34,30 @@
</child> </child>
</object> </object>
</child> </child>
<child>
<object class="AdwActionRow" id="hw_fp_pwr">
<property name="title">Fingerprint</property>
<property name="visible">False</property>
<child>
<object class="GtkBox">
<property name="halign">end</property>
<property name="homogeneous">True</property>
<property name="spacing">5</property>
<property name="valign">center</property>
<child>
<object class="GtkButton" id="hw_fp_pwr_en">
<property name="label">Enable</property>
</object>
</child>
<child>
<object class="GtkButton" id="hw_fp_pwr_dis">
<property name="label">Disable</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child> <child>
<object class="AdwActionRow" id="hw_priv_cam"> <object class="AdwActionRow" id="hw_priv_cam">
<property name="subtitle">Use Privacy Switch</property> <property name="subtitle">Use Privacy Switch</property>
@@ -65,23 +97,35 @@
</object> </object>
</child> </child>
<child> <child>
<object class="AdwActionRow" id="hw_fp_pwr"> <object class="AdwActionRow" id="hw_lid_open">
<property name="title">Fingerprint</property> <property name="title">Lid Open</property>
<property name="visible">False</property>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="halign">end</property> <property name="halign">end</property>
<property name="homogeneous">True</property> <property name="homogeneous">True</property>
<property name="spacing">5</property>
<property name="valign">center</property> <property name="valign">center</property>
<child> <child>
<object class="GtkButton" id="hw_fp_pwr_en"> <object class="GtkSwitch" id="hw_lid_open_sw">
<property name="label">Enable</property> <property name="active">True</property>
<property name="sensitive">False</property>
</object> </object>
</child> </child>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="hw_pwr_btn">
<property name="title">Power Button Pressed</property>
<child>
<object class="GtkBox">
<property name="halign">end</property>
<property name="homogeneous">True</property>
<property name="valign">center</property>
<child> <child>
<object class="GtkButton" id="hw_fp_pwr_dis"> <object class="GtkSwitch" id="hw_pwr_btn_sw">
<property name="label">Disable</property> <property name="active">True</property>
<property name="sensitive">False</property>
</object> </object>
</child> </child>
</object> </object>

View File

@@ -69,52 +69,6 @@
<property name="selectable">False</property> <property name="selectable">False</property>
<property name="subtitle">These options break normal functionality</property> <property name="subtitle">These options break normal functionality</property>
<property name="title">Advanced Options</property> <property name="title">Advanced Options</property>
<child>
<object class="AdwPreferencesGroup">
<property name="description">When using these options, the power LED may not turn off with the computer.</property>
<property name="margin-bottom">5</property>
<property name="margin-end">5</property>
<property name="margin-start">5</property>
<property name="margin-top">5</property>
<property name="title">Power Button LED</property>
<child>
<object class="AdwComboRow" id="led_pwr_colour">
<property name="model">
<object class="GtkStringList">
<items>
<item>Auto</item>
<item>Off</item>
</items>
</object>
</property>
<property name="title">Colour</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<property name="description">When using these options, the charging indicator will no longer indicate charging.</property>
<property name="margin-bottom">5</property>
<property name="margin-end">5</property>
<property name="margin-start">5</property>
<property name="margin-top">5</property>
<property name="title">Charging Indicators</property>
<child>
<object class="AdwComboRow" id="led_chg_colour">
<property name="model">
<object class="GtkStringList">
<items>
<item>Auto</item>
<item>Off</item>
</items>
</object>
</property>
<property name="title">Colour</property>
</object>
</child>
</object>
</child>
</object> </object>
</child> </child>
<style> <style>

View File

@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.96.1 --> <!-- Created with Cambalache 0.96.3 -->
<interface> <interface>
<!-- interface-name thermals.ui --> <!-- interface-name thermals.ui -->
<!-- interface-description The Thermals page for YAFI --> <!-- interface-description The Thermals page for YAFI -->
@@ -92,6 +92,12 @@
<property name="visible">False</property> <property name="visible">False</property>
</object> </object>
</child> </child>
<child>
<object class="AdwExpanderRow" id="fan_set_points">
<property name="selectable">False</property>
<property name="title">Fan Set Points</property>
</object>
</child>
<style> <style>
<class name="boxed-list"/> <class name="boxed-list"/>
</style> </style>

View File

@@ -1,11 +1,11 @@
<?xml version='1.0' encoding='UTF-8' standalone='no'?> <?xml version='1.0' encoding='UTF-8' standalone='no'?>
<!DOCTYPE cambalache-project SYSTEM "cambalache-project.dtd"> <!DOCTYPE cambalache-project SYSTEM "cambalache-project.dtd">
<!-- Created with Cambalache 0.96.1 --> <!-- Created with Cambalache 0.96.3 -->
<cambalache-project version="0.96.0" target_tk="gtk-4.0"> <cambalache-project version="0.96.0" target_tk="gtk-4.0">
<ui template-class="YafiWindow" filename="yafi.ui" sha256="9d1b2f030e4a816eb0b1aa53ae1d80c5b50a2f4646e32c7a64803eb6f6ed3947"/> <ui template-class="YafiWindow" filename="yafi.ui" sha256="9d1b2f030e4a816eb0b1aa53ae1d80c5b50a2f4646e32c7a64803eb6f6ed3947"/>
<ui template-class="ThermalsPage" filename="thermals.ui" sha256="e301e65649005315ff60d250b60a47f6250ad6feb27db104051fcf0143cde173"/> <ui template-class="ThermalsPage" filename="thermals.ui" sha256="89f5b68da04abad587d8b949d18357cd956313680e663b10e5d42697f9bfbf6e"/>
<ui template-class="LedsPage" filename="leds.ui" sha256="0350d22d570de039d63602ba40925f17fff6680fd5909d2ebf19600f351eb0f2"/> <ui template-class="LedsPage" filename="leds.ui" sha256="abc3ee759974a5c92feb48cc258dbe7271d0402facf71fd5e779f2bb1a277e16"/>
<ui template-class="BatteryLimiterPage" filename="battery-limiter.ui" sha256="b5d41b19cb1fb7ca5b4bcfae43244e54111f5e8d8c51d95448d6a92b5185d2c4"/> <ui template-class="BatteryLimiterPage" filename="battery-limiter.ui" sha256="3a50b0dea08b9acbaa389d7d7a38bd94970fdc79207ef10638f722f52d9425cd"/>
<ui template-class="HardwarePage" filename="hardware.ui" sha256="f4deec4e38e683fde97656802dbfb2a638ab46a0e36af5c9a37f277f49e2aabb"/> <ui template-class="HardwarePage" filename="hardware.ui" sha256="37ea282198d9f60435f80e4adf8256cd2249e590dcad4b63af634d828673f1bf"/>
<ui template-class="BatteryPage" filename="battery.ui" sha256="d495280cb543a26cdee1c2939e5af980d8d3878c326e360eeab4f05195cdbdc9"/> <ui template-class="BatteryPage" filename="battery.ui" sha256="d495280cb543a26cdee1c2939e5af980d8d3878c326e360eeab4f05195cdbdc9"/>
</cambalache-project> </cambalache-project>

View File

@@ -18,8 +18,7 @@
# #
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
from gi.repository import Adw from gi.repository import Gtk, Adw
from gi.repository import Gtk
@Gtk.Template(resource_path='/au/stevetech/yafi/ui/yafi.ui') @Gtk.Template(resource_path='/au/stevetech/yafi/ui/yafi.ui')
class YafiWindow(Adw.ApplicationWindow): class YafiWindow(Adw.ApplicationWindow):

Binary file not shown.