Merge pull request #18 from tr1xem/macos

Misc Fix
This commit was merged in pull request #18.
This commit is contained in:
sankalp authored and GitHub committed 2025-08-03 18:43:41 +05:45
commit aec1c8bc90
21 files changed
+862 -390

No files matched your search

+5 -2
View File
@@ -1,3 +1,6 @@
<svg width="24" height="24" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="m11.5 5c-0.277 0-0.5 0.223-0.5 0.5v4.875l-1.719-1.5c-0.312-0.273-0.757-0.22-1.03 0.094a0.753 0.753 0 0 0 0.062 1.062l2.25 1.969-2.25 1.969a0.753 0.753 0 0 0-0.063 1.062c0.274 0.313 0.719 0.367 1.031 0.094l1.72-1.5v4.875c0 0.277 0.222 0.5 0.5 0.5 0.282 0 0.437-0.02 0.655-0.188l3.532-3.156a0.78 0.78 0 0 0 0.218-0.375 0.745 0.745 0 0 0 0.032-0.281 0.723 0.723 0 0 0-0.032-0.156 0.78 0.78 0 0 0-0.218-0.375l-2.813-2.47 2.813-2.468a0.78 0.78 0 0 0 0.218-0.375 0.712 0.712 0 0 0 0-0.437 0.78 0.78 0 0 0-0.218-0.375l-3.532-3.157c-0.199-0.16-0.427-0.187-0.656-0.187zm0.5 2.063 2.094 1.875-2.094 1.812zm0 6.187 2.094 1.813-2.094 1.875z" color="#bebebe" fill="#f2f2f2" overflow="visible"/>
<svg width="16" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<style id="current-color-scheme" type="text/css">.ColorScheme-Text { color:#dedede; } .ColorScheme-Highlight { color:#5294e2; }</style>
</defs>
<path d="m7.2949 1.0449a0.50005 0.50005 0 0 0-0.29492 0.45508v5.2852l-2.7344-1.709a0.5 0.5 0 0 0-0.68945 0.1582 0.5 0.5 0 0 0 0.1582 0.68945l3.2656 2.041v0.070313l-3.2656 2.041a0.5 0.5 0 0 0-0.1582 0.68945 0.5 0.5 0 0 0 0.68945 0.1582l2.7344-1.709v5.2852a0.50005 0.50005 0 0 0 0.83203 0.37305l4.5-4a0.50005 0.50005 0 0 0-0.06641-0.79688l-3.3223-2.0762 3.3223-2.0762a0.50005 0.50005 0 0 0 0.06641-0.79688l-4.5-4a0.50005 0.50005 0 0 0-0.53711-0.082031zm0.70508 1.5684 3.1699 2.8164-3.1699 1.9805zm0 5.9766 3.1699 1.9805-3.1699 2.8164z" class="ColorScheme-Text" fill="currentColor"/>
</svg>

Before

Width:  |  Height:  |  Size: 777 B

After

Width:  |  Height:  |  Size: 822 B

+6 -29
View File
@@ -1,30 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg6"
version="1.1"
width="24"
height="24">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<path
id="path2"
d="M 6.3515625,4.7363281 5.4121094,5.6777344 17.601562,17.867188 18.541016,16.925781 13.267578,11.652344 15.6875,9.53125 c 0.106935,-0.1017801 0.18279,-0.2318176 0.21875,-0.375 0.04605,-0.1421978 0.04605,-0.2953022 0,-0.4375 C 15.87029,8.5755676 15.794435,8.4455301 15.6875,8.34375 L 12.15625,5.1875 C 11.95725,5.0275 11.729,5 11.5,5 11.223,5 11,5.223 11,5.5 V 9.3847656 Z M 12,7.0625 14.09375,8.9375 12.195312,10.580078 12,10.384766 Z M 10.494141,12.060547 8.3125,13.96875 c -0.310445,0.276247 -0.3384165,0.751761 -0.0625,1.0625 0.273,0.313 0.71825,0.36675 1.03125,0.09375 l 1.720703,-1.5 V 18.5 c 0,0.277 0.222,0.5 0.5,0.5 0.282,0 0.436297,-0.0195 0.654297,-0.1875 L 14.84375,16.410156 13.779297,15.345703 12,16.9375 v -3.371094 z"
style="color:#bebebe;overflow:visible;fill:#f2f2f2;marker:none" />
<svg width="16" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg">
<style id="current-color-scheme" type="text/css">.ColorScheme-Text {
color:#dedede;
}</style>
<rect class="ColorScheme-Text" transform="rotate(45)" x="1.3137" y="-.5" width="20" height="1" rx=".5" ry=".5" fill="currentColor" stroke-width="1.118"/>
<path class="ColorScheme-Text" d="m7.2953 1.0449a0.50005 0.50005 0 0 0-0.29492 0.45508v5.2852l-2.7344-1.709a0.5 0.5 0 0 0-0.68945 0.1582 0.5 0.5 0 0 0 0.1582 0.68945l3.2656 2.041v0.07031l-3.2656 2.041a0.5 0.5 0 0 0-0.1582 0.68945 0.5 0.5 0 0 0 0.68945 0.1582l2.7344-1.709v5.2852a0.50005 0.50005 0 0 0 0.83203 0.37305l4.5-4a0.50005 0.50005 0 0 0-0.06641-0.79688l-3.3223-2.0762 3.3223-2.0762a0.50005 0.50005 0 0 0 0.06641-0.79688l-4.5-4a0.50005 0.50005 0 0 0-0.53711-0.08203zm0.70508 1.5684 3.1699 2.8164-3.1699 1.9805zm0 5.9766 3.1699 1.9805-3.1699 2.8164z" fill="currentColor" opacity=".35"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 943 B

@@ -0,0 +1,7 @@
<svg width="16" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<style id="current-color-scheme" type="text/css">.ColorScheme-Text { color:#dedede; } .ColorScheme-Highlight { color:#5294e2; }</style>
</defs>
<path d="m7.4805 1.002a0.50005 0.50005 0 0 0-0.18555 0.042969 0.50005 0.50005 0 0 0-0.29492 0.45508v5.2852l-2.7344-1.709a0.5 0.5 0 0 0-0.68945 0.1582 0.5 0.5 0 0 0 0.1582 0.68945l3.2656 2.041v0.070312l-3.2656 2.041a0.5 0.5 0 0 0-0.1582 0.68945 0.5 0.5 0 0 0 0.68945 0.1582l2.7344-1.709v5.2852a0.50005 0.50005 0 0 0 0.83203 0.37305l1.168-1.0391v-0.83398c0-0.21977 0.042063-0.42278 0.11719-0.60742l-1.1172 0.99414v-4.7969l2.7383 1.7109c0.18696-0.29042 0.41455-0.54722 0.67969-0.75391l-2.4746-1.5469 3.3223-2.0762a0.50005 0.50005 0 0 0 0.066406-0.79688l-4.5-4a0.50005 0.50005 0 0 0-0.35156-0.125zm0.51953 1.6113 3.1699 2.8164-3.1699 1.9805v-4.7969z" class="ColorScheme-Text" fill="currentColor"/>
<path d="m13 10c-1.108 0-2 0.892-2 2-0.554 0-1 0.446-1 1v2c0 0.554 0.446 1 1 1h4c0.554 0 1-0.446 1-1v-2c0-0.554-0.446-1-1-1 0-1.108-0.892-2-2-2zm0 1c0.554 0 1 0.446 1 1h-2c0-0.554 0.446-1 1-1z" class="ColorScheme-Text" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+7 -5
View File
@@ -1,6 +1,8 @@
<svg width="24" height="24" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<style id="current-color-scheme" type="text/css">.ColorScheme-Text { color:#dedede; }</style>
</defs>
<path class="ColorScheme-Text" d="m12 7.0206c-2.6432 0-5.1397 1.1665-6.85 3.2009a0.63845 0.63845 0 0 0 0.49005 1.0491c0.18222 0 0.36305-0.0773 0.48971-0.22742 1.4657-1.7438 3.6057-2.7446 5.8703-2.7446 2.2646 0 4.4046 1.0012 5.8703 2.7446 0.12631 0.15116 0.30714 0.22777 0.48971 0.22777a0.63776 0.63776 0 0 0 0.4897-1.0495c-1.7097-2.0344-4.2068-3.2009-6.8504-3.2009zm0 2.707c-1.8877 0-3.6709 0.83378-4.8922 2.2863a0.63894 0.63894 0 1 0 0.97838 0.82204 5.1055 5.1055 0 0 1 3.9135-1.8301c1.5102 0 2.9369 0.66744 3.9142 1.8301 0.12631 0.15116 0.30784 0.22777 0.48971 0.22777a0.63845 0.63845 0 0 0 0.48833-1.0495c-1.2217-1.4529-3.0038-2.2867-4.8922-2.2867zm0 2.8126a3.8272 3.8272 0 0 0-2.9358 1.3704 0.63845 0.63845 0 0 0 0.079374 0.90038 0.63603 0.63603 0 0 0 0.90038-0.07765 2.5507 2.5507 0 0 1 1.9561-0.91453c0.75475 0 1.4677 0.33303 1.9568 0.91453a0.63707 0.63707 0 0 0 0.90004 0.07765 0.63845 0.63845 0 0 0 0.07937-0.90038 3.8272 3.8272 0 0 0-2.9362-1.3704zm-0.05452 2.4264c-0.49971 0.04832-0.98079 0.42172-0.99736 0.97838a1.0522 1.0522 0 0 0 2.1041 0c-0.08869-0.74716-0.6067-1.026-1.1068-0.97838z" fill="currentColor"/>
<svg width="16" height="16" version="1.1" xmlns="http://www.w3.org/2000/svg">
<g fill="#dedede">
<path d="m8 3c-2.8405-3e-7 -5.4324 1.0071-7.4863 2.6582a0.5 0.5 0 0 0-0.095703 0.072266 0.5 0.5 0 0 0-0.1543 0.35938 0.5 0.5 0 0 0 0.5 0.5 0.5 0.5 0 0 0 0.31836-0.11328c1.891-1.5388 4.2898-2.4766 6.918-2.4766 2.6282-3e-7 5.0269 0.93776 6.918 2.4766a0.5 0.5 0 0 0 0.31836 0.11328 0.5 0.5 0 0 0 0.5-0.5 0.5 0.5 0 0 0-0.1543-0.35938 0.5 0.5 0 0 0-0.095703-0.072266c-2.0539-1.6511-4.6459-2.6582-7.4863-2.6582z" fill-rule="evenodd" style="paint-order:stroke fill markers"/>
<path d="m8 9c-1.3525-2e-7 -2.5832 0.46891-3.5859 1.2246-0.11034 0.09497-0.16795 0.23918-0.16797 0.38477 0 0.27614 0.22386 0.5 0.5 0.5 0.12436-3.26e-4 0.24413-0.04698 0.33594-0.13086 0.82215-0.60306 1.8199-0.97852 2.918-0.97852 1.0981-2e-7 2.0958 0.37546 2.918 0.97852 0.091809 0.083879 0.21158 0.13053 0.33594 0.13086 0.27614 0 0.5-0.22386 0.5-0.5-1.6e-5 -0.14559-0.057625-0.2898-0.16797-0.38477-1.0027-0.7557-2.2334-1.2246-3.5859-1.2246z"/>
<path d="m8 6c-2.0731 0-3.9681 0.71726-5.4883 1.8965a0.5 0.5 0 0 0-0.10156 0.074219 0.5 0.5 0 0 0-0.15625 0.36133 0.5 0.5 0 0 0 0.5 0.5 0.5 0.5 0 0 0 0.32031-0.11523c1.3588-1.0688 3.0627-1.7168 4.9258-1.7168 1.8631-2e-7 3.567 0.64796 4.9258 1.7168a0.5 0.5 0 0 0 0.32031 0.11523 0.5 0.5 0 0 0 0.5-0.5 0.5 0.5 0 0 0-0.15625-0.36133 0.5 0.5 0 0 0-0.10156-0.074219c-1.5202-1.1792-3.4152-1.8965-5.4883-1.8965z" fill-rule="evenodd" style="paint-order:stroke fill markers"/>
<circle cx="8" cy="13" r="1" fill-rule="evenodd" style="paint-order:stroke fill markers"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File
File mode changed.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

+1 -5
View File
@@ -1,5 +1 @@
<svg viewBox="-4 -4 32 32" width="24" height="24" stroke="#fff" stroke-width="2" fill="none"
stroke-linecap="round" stroke-linejoin="round" class="css-i6dzq1">
<circle cx="11" cy="11" r="8"></circle>
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M7.452 2C4.446 2 2 4.439 2 7.435c0 2.997 2.446 5.436 5.452 5.436 1.31 0 2.514-.464 3.455-1.235l3.547 3.537.62-.619-3.536-3.525a5.403 5.403 0 0 0 1.365-3.594C12.903 4.44 10.457 2 7.452 2Zm0 .875a4.561 4.561 0 1 1 0 9.121 4.561 4.561 0 1 1 0-9.121z" style="fill:#dedede;fill-opacity:1"/></svg>

Before

Width:  |  Height:  |  Size: 261 B

After

Width:  |  Height:  |  Size: 363 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

+96 -83
View File
@@ -1,85 +1,98 @@
{
"launcher_config": {
"em": {
"icon": "emoji",
"description": "Emoji - Search and copy emojis"
},
"clip": {
"icon": "clipboard",
"description": "Clipboard - Search and manage clipboard history"
},
"=": {
"examples": ["= 10*5", "= 2^8", "= sin(30)"],
"icon": "calculator",
"description": "Quick Math - Fast mathematical expressions"
},
"app": {
"icon": "apps",
"description": "Applications - Launch installed applications"
},
"bin": {
"icon": "terminal",
"description": "Bins - Search and run executable binaries"
},
"power": {
"icon": "shutdown",
"description": "Power - System power management and session control"
},
"caffeine": {
"examples": ["caffeine 30m", "caffeine 1h", "caffeine 2h", "caffeine on"],
"icon": "coffee",
"description": "Caffeine - Prevent system from going idle"
},
"sc": {
"icon": "toolbox",
"description": "Screencapture - Record screen and audio"
},
"wall": {
"icon": "wallpapers",
"description": "Wallpapers - Set wallpapers, and tons of features"
},
"?": {
"icon": "world",
"description": "Quick Web Search - Fast web search with question mark",
"examples": ["? cats", "? google cats", "? youtube music"]
},
"remind": {
"icon": "timer_on",
"description": "Reminders - Set time-based reminders with notifications"
},
"otp": {
"icon": "auth",
"description": "Manage TOTP codes and 2FA authentication"
},
"pass": {
"icon": "key",
"description": "Password Manager - Search and manage passwords"
},
"bm": {
"icon": "bookmark",
"description": "Bookmarks - Search and manage bookmarks"
},
"script": {
"icon": "terminal",
"description": "Bash Scripts - Manage and execute bash scripts"
},
"bash": {
"icon": "terminal",
"description": "Bash Scripts - Manage and execute bash scripts"
},
"sh": {
"icon": "terminal",
"description": "Bash Scripts - Manage and execute bash scripts"
},
"tmux": {
"icon": "terminal",
"description": "Tmux Manager - Create, attach, rename, and kill tmux sessions"
}
},
"settings": {
"max_examples_shown": 2,
"default_icon": "apps",
"fallback_example_template": "{trigger} <search>",
"config_version": "1.0"
}
"launcher_config": {
"em": {
"icon": "emoji-people-symbolic",
"description": "Emoji - Search and copy emojis"
},
"clip": {
"icon": "app.getclipboard.Clipboard",
"description": "Clipboard - Search and manage clipboard history"
},
"=": {
"examples": [
"= 10*5",
"= 2^8",
"= sin(30)"
],
"icon": "calculator",
"description": "Quick Math - Fast mathematical expressions"
},
"app": {
"icon": "apps",
"description": "Applications - Launch installed applications"
},
"bin": {
"icon": "terminal",
"description": "Bins - Search and run executable binaries"
},
"power": {
"icon": "shutdown",
"description": "Power - System power management and session control"
},
"caffeine": {
"examples": [
"caffeine 30m",
"caffeine 1h",
"caffeine 2h",
"caffeine on"
],
"icon": "caffeine",
"description": "Caffeine - Prevent system from going idle"
},
"sc": {
"icon": "cs-screen",
"description": "Screencapture - Record screen and audio"
},
"wall": {
"icon": "daily-wallpaper",
"description": "Wallpapers - Set wallpapers, and tons of features"
},
"?": {
"icon": "search-symbolic",
"description": "Quick Web Search - Fast web search with question mark",
"examples": [
"? cats",
"? google cats",
"? youtube music"
]
},
"remind": {
"icon": "alarm-timer",
"description": "Reminders - Set time-based reminders with notifications"
},
"otp": {
"icon": "auth-otp-symbolic",
"description": "Manage TOTP codes and 2FA authentication"
},
"pass": {
"icon": "nextcloud-password-client",
"description": "Password Manager - Search and manage passwords"
},
"bm": {
"icon": "bookmark-add-symbolic",
"description": "Bookmarks - Search and manage bookmarks"
},
"script": {
"icon": "terminal",
"description": "Bash Scripts - Manage and execute bash scripts"
},
"bash": {
"icon": "terminal",
"description": "Bash Scripts - Manage and execute bash scripts"
},
"sh": {
"icon": "terminal",
"description": "Bash Scripts - Manage and execute bash scripts"
},
"tmux": {
"icon": "terminal",
"description": "Tmux Manager - Create, attach, rename, and kill tmux sessions"
}
},
"settings": {
"max_examples_shown": 2,
"default_icon": "apps",
"fallback_example_template": "{trigger} <search>",
"config_version": "1.0"
}
}
+94 -1
View File
@@ -33,7 +33,7 @@ tooltip {
border-radius: 16px;
border-color: var(--surface);
background-color: var(--shadow);
animation: tooltipShow 0.25s cubic-bezier(0.5, 0.25, 0, 1);
/* animation: tooltipShow 0.25s cubic-bezier(0.5, 0.25, 0, 1); */
}
@keyframes tooltipShow {
@@ -71,3 +71,96 @@ menu > menuitem:hover {
menu > menuitem:hover > label {
color: var(--shadow);
}
#weather-widget label{
font-family: "SF Pro Rounded";
/* font-size: 20px; */
font-weight: 600;
margin-left: 10px;
}
#city {
margin-top: 10px;
font-size: 20px;
}
#temperature {
font-size: 50px;
}
#condition-emoji{
margin-top: 10px;
font-size: 16px;
}
#condition {
font-size: 15px;
}
#feels-like {
font-size: 15px;
}
/* # */
#date-widget label {
font-family: "SF Pro Rounded";
margin-top: 10px;
}
#day label,
#month label{
color: var(--foreground);
padding: 5px;
margin-top: 10px;
font-size: 30px;
color: alpha(#fff, 0.7);
font-weight: 600;
}
#date label{
color: alpha(#fff, 0.7);
margin-top: -10px;
font-size: 90px;
font-weight: 600;
}
#day label{
color: alpha(#FF0000, 0.7);
}
#box-widget{
background-color: alpha(#232323, 1);
margin: 20px 20px 20px 20px;
min-width: 170px;
min-height: 170px;
border-radius: 16px;
}
#box-widget-2{
background-color: alpha(#425D8A, 1);
min-width: 170px;
min-height: 170px;
border-radius: 16px;
}
+6 -1
View File
@@ -1,3 +1,4 @@
from fabric.core import widgets
import setproctitle
from loguru import logger
@@ -7,6 +8,7 @@ from fabric.utils import get_relative_path, monitor_file
from modules.dock import Dock
from modules.launcher.main import Launcher
from modules.notification.notification import ModusNoti
from modules.widget import Deskwidgets
from modules.osd import OSD
# from modules.corners import Corners
@@ -41,6 +43,7 @@ if __name__ == "__main__":
panel.launcher = launcher
osd = OSD()
widgets = Deskwidgets()
# Set corners visibility based on config
# corners_visible = config.get("corners_visible", True)
# corners.set_visible(corners_visible)
@@ -50,7 +53,9 @@ if __name__ == "__main__":
_ = css_file.connect("changed", lambda *_: set_css())
# Make sure corners is added to the app
app = Application(f"{APP_NAME}", panel, dock, switcher, launcher, modusnoti, osd)
app = Application(
f"{APP_NAME}", panel, dock, switcher, launcher, modusnoti, osd, widgets
)
def set_css():
app.set_stylesheet_from_file(
+20 -19
View File
@@ -88,7 +88,6 @@ class Player(Box):
f"background-image:url('{data.HOME_DIR}/.current.wall')"
)
self.children = [
self.album_cover,
Box(
@@ -201,9 +200,6 @@ class Player(Box):
return
self.duration = dur
def on_seek(self, sender, ratio):
pos = ratio * self.duration # duration in seconds
self._player.set_position(int(pos))
@@ -269,7 +265,7 @@ class Player(Box):
self._is_updating = True
update_func, args, kwargs = self._update_queue.pop(0)
try:
update_func(*args, **kwargs)
except Exception as e:
@@ -284,13 +280,14 @@ class Player(Box):
"""Finish current update and process next item in queue."""
self._is_updating = False
self._update_timeout_id = None
if self._update_queue:
self._process_queue()
return False
def _handle_thumbnail(self, metadata, player):
"""Queue thumbnail update to prevent overlapping operations."""
def _update_thumbnail():
keys = metadata.keys()
player_name = player.props.player_name
@@ -305,16 +302,24 @@ class Player(Box):
logger.debug(f"Found MPRIS art for {player_name}: {art_url}")
# Check for browser players and YouTube URLs
elif player_name in ["firefox", "chromium", "vivaldi", "brave"] and "xesam:url" in keys:
elif (
player_name in ["firefox", "chromium", "vivaldi", "brave"]
and "xesam:url" in keys
):
webpage_url = metadata["xesam:url"]
if webpage_url and "youtube.com" in webpage_url:
# Simple YouTube thumbnail extraction
import re
match = re.search(r"(?:v=|/)([a-zA-Z0-9_-]{11})", webpage_url)
if match:
video_id = match.group(1)
new_thumbnail = f"https://img.youtube.com/vi/{video_id}/hqdefault.jpg"
logger.debug(f"Found YouTube thumbnail for {player_name}: {new_thumbnail}")
new_thumbnail = (
f"https://img.youtube.com/vi/{video_id}/hqdefault.jpg"
)
logger.debug(
f"Found YouTube thumbnail for {player_name}: {new_thumbnail}"
)
# Only update if thumbnail has changed
if new_thumbnail and new_thumbnail != self._current_thumbnail:
@@ -324,20 +329,20 @@ class Player(Box):
elif not new_thumbnail and self._current_thumbnail:
# Reset to default if no thumbnail found
self._current_thumbnail = None
self.album_cover.set_style(f"background-image:url('{data.HOME_DIR}/.current.wall')")
self.album_cover.set_style(
f"background-image:url('{data.HOME_DIR}/.current.wall')"
)
logger.debug(f"Reset to default wallpaper for {player_name}")
self._queue_update(_update_thumbnail)
def handle_next(self, player):
def _do_next():
try:
self._player._player.next()
except Exception as e:
logger.warning(f"Failed to go to next track: {e}")
self._queue_update(_do_next)
def handle_prev(self, player):
@@ -346,11 +351,9 @@ class Player(Box):
self._player._player.previous()
except Exception as e:
logger.warning(f"Failed to go to previous track: {e}")
self._queue_update(_do_prev)
def handle_play_pause(self, player):
def _do_play_pause():
is_playing = (
@@ -431,9 +434,7 @@ class Placeholder(Box):
children=[
CenterBox(
name="details",
center_children=Label(
label="Nothing Playing", style="color:black;"
),
center_children=Label(label="Nothing Playing"),
)
],
),
+15 -1
View File
@@ -1,6 +1,7 @@
import json
import re
from typing import List
import subprocess
from fabric.utils import DesktopApp
from fabric.utils.helpers import get_desktop_applications, get_relative_path
@@ -155,8 +156,21 @@ class ApplicationsPlugin(PluginBase):
pattern = ".*".join(re.escape(char) for char in query)
return bool(re.search(pattern, text, re.IGNORECASE))
import subprocess
def _launch_application(self, app: DesktopApp):
app.launch()
print("Original:", app.command_line)
# Remove ALL % codes (e.g., %u, %U, %f, %F, %i, %c, etc.)
cleaned_command = re.sub(r"%\w+", "", app.command_line).strip()
print("Cleaned:", cleaned_command)
# Final command with hyprctl dispatch
final_command = f"hyprctl dispatch exec 'uwsm app -- {cleaned_command}'"
subprocess.Popen(final_command, shell=True)
# app.launch()
def _get_all_applications(self) -> List[Result]:
"""Get a list of all available applications."""
+38 -229
View File
@@ -1,5 +1,6 @@
import os
from fabric.utils import get_relative_path
from gi.repository import Gdk, GdkPixbuf, GLib, Gtk # type: ignore
from loguru import logger
@@ -103,7 +104,7 @@ class NotificationWidget(Box):
if "file://" in notification.app_icon
else Image(
name="notification-icon",
icon_name="dialog-information-symbolic" or notification.app_icon,
icon_name="notifications" or notification.app_icon,
icon_size=24,
)
)
@@ -175,31 +176,24 @@ class NotificationWidget(Box):
ellipsization="end",
)
if notification.body
else Box()
else Label(
markup="",
h_align="start",
ellipsization="end",
)
),
],
),
Box(h_expand=True),
Box(
orientation="v",
children=[
self.create_close_button() if self.show_close_button else Box(),
Box(v_expand=True),
],
Button(
name="notification-close-button",
image=CustomImage(icon_name="close-symbolic", icon_size=18),
visible=True, # Initially hidden
on_clicked=lambda *_: self.notification.close("dismissed-by-user"),
),
],
)
def create_close_button(self):
if self.close_button is None:
self.close_button = Button(
name="notification-close-button",
visible=False, # Initially hidden
on_clicked=lambda *_: self.notification.close("dismissed-by-user"),
child=Label(label="×", name="close-button-label"),
)
return self.close_button
def _on_enter_notify(self, widget, event):
self._is_hovered = True
if self.close_button:
@@ -215,12 +209,12 @@ class NotificationWidget(Box):
return False
def get_pixbuf(self, icon_path, width, height):
if icon_path.startswith("file://"):
if icon_path.startswith("file://") and os.path.exists(icon_path):
icon_path = icon_path[7:]
if not os.path.exists(icon_path):
logger.warning(f"Icon path does not exist: {icon_path}")
return None
icon_path = get_relative_path("../../config/assets/icons/notification.png")
try:
pixbuf = GdkPixbuf.Pixbuf.new_from_file(icon_path)
@@ -297,18 +291,20 @@ class NotificationRevealer(SlideRevealer):
self._is_closing = False
# Enhanced swipe detection variables for Android-style animation
self._drag_start_x = 0
self._drag_start_y = 0
self._drag_start_x = 0
self._is_dragging = False
self._swipe_threshold = 80 # Distance to trigger auto-dismiss
self._swipe_velocity_threshold = 150 # Velocity to trigger dismiss even on shorter swipes
self._swipe_velocity_threshold = (
150 # Velocity to trigger dismiss even on shorter swipes
)
self._swipe_in_progress = False
self._current_offset = 0
self._last_drag_time = 0
self._drag_velocity = 0
self._spring_back_duration = 200 # Duration for spring-back animation
self._dismiss_threshold = 0.3 # Dismiss if swiped 30% of width
# Animation state
self._animation_in_progress = False
self._spring_timer_id = None
@@ -324,15 +320,10 @@ class NotificationRevealer(SlideRevealer):
child=self.notif_box,
)
self.event_box.connect("button-press-event", self._on_button_press)
self.event_box.connect("button-release-event", self._on_button_release)
self.event_box.connect("motion-notify-event", self._on_motion)
self.event_box.connect("realize", self._on_realize)
super().__init__(
child=self.event_box,
direction="right",
duration=350, # Optimized duration for macOS-like feel
duration=600, # Optimized duration for macOS-like feel
)
smooth_revealer_animation(self)
@@ -340,90 +331,7 @@ class NotificationRevealer(SlideRevealer):
# Connect our own handler that manages the slide animation
self.notification.connect("closed", self.on_resolved)
def _on_realize(self, widget):
"""Setup CSS provider when widget is realized"""
try:
self._css_provider = Gtk.CssProvider()
context = widget.get_style_context()
context.add_provider(self._css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
except Exception as e:
logger.warning(f"Could not setup CSS provider for notification animation: {e}")
def _apply_transform(self, offset_x, opacity=1.0, scale=1.0):
"""Apply transform to the notification widget for smooth animation"""
if not self.event_box or not self.event_box.get_realized():
return
# Clamp values
offset_x = max(0, offset_x) # Only allow rightward movement
opacity = max(0.1, min(1.0, opacity)) # Keep some visibility
scale = max(0.8, min(1.0, scale)) # Subtle scale effect
try:
if self._css_provider:
# Apply CSS transform using the provider
css_data = f"""
* {{
margin-left: {int(offset_x)}px;
opacity: {opacity};
transform: scale({scale});
}}
"""
self._css_provider.load_from_data(css_data.encode('utf-8'))
else:
# Fallback: use widget margins for offset
current_margin = self.event_box.get_margin_start()
if current_margin != int(offset_x):
self.event_box.set_margin_start(int(offset_x))
# Set opacity directly on the widget
self.event_box.set_opacity(opacity)
except Exception as e:
# Final fallback: just use margin
try:
self.event_box.set_margin_start(int(offset_x))
self.event_box.set_opacity(opacity)
except:
pass
def _animate_spring_back(self, start_offset, target_offset=0, duration=None):
"""Animate the notification springing back to its original position"""
if duration is None:
duration = self._spring_back_duration
if self._spring_timer_id:
GLib.source_remove(self._spring_timer_id)
start_time = GLib.get_monotonic_time() / 1000
offset_diff = target_offset - start_offset
def animate_step():
current_time = GLib.get_monotonic_time() / 1000
elapsed = current_time - start_time
progress = min(1.0, elapsed / duration)
# Use easing function for spring-like animation
eased_progress = self._ease_out_back(progress)
current_offset = start_offset + (offset_diff * eased_progress)
# Calculate opacity and scale based on offset
max_offset = NOTIFICATION_WIDTH * 0.8
offset_ratio = abs(current_offset) / max_offset
opacity = 1.0 - (offset_ratio * 0.3) # Fade slightly
scale = 1.0 - (offset_ratio * 0.05) # Slight scale down
self._apply_transform(current_offset, opacity, scale)
if progress >= 1.0:
self._animation_in_progress = False
self._current_offset = target_offset
return False
return True
self._animation_in_progress = True
self._spring_timer_id = GLib.timeout_add(16, animate_step) # ~60fps
def _ease_out_back(self, t):
"""Easing function for spring-back animation"""
@@ -435,28 +343,30 @@ class NotificationRevealer(SlideRevealer):
"""Animate the notification sliding out completely - now much faster"""
target_offset = NOTIFICATION_WIDTH + 50 # Slide completely out of view
duration = 120 # Much faster dismiss animation (was 250)
if self._spring_timer_id:
GLib.source_remove(self._spring_timer_id)
start_time = GLib.get_monotonic_time() / 1000
offset_diff = target_offset - start_offset
def animate_step():
current_time = GLib.get_monotonic_time() / 1000
elapsed = current_time - start_time
progress = min(1.0, elapsed / duration)
# Use faster easing for snappier exit
eased_progress = progress * progress # Quadratic ease out - faster than cubic
eased_progress = (
progress * progress
) # Quadratic ease out - faster than cubic
current_offset = start_offset + (offset_diff * eased_progress)
# Fade out and scale down during dismiss
opacity = 1.0 - (progress * 1.2) # Faster fade out
scale = 1.0 - (progress * 0.15) # Slightly more scale change
scale = 1.0 - (progress * 0.15) # Slightly more scale change
self._apply_transform(current_offset, opacity, scale)
if progress >= 1.0:
# Trigger the actual notification dismissal immediately
try:
@@ -464,22 +374,24 @@ class NotificationRevealer(SlideRevealer):
except:
pass
return False
return True
self._animation_in_progress = True
self._spring_timer_id = GLib.timeout_add(12, animate_step) # Higher fps for smoother animation
self._spring_timer_id = GLib.timeout_add(
12, animate_step
) # Higher fps for smoother animation
def _calculate_drag_velocity(self, current_x):
"""Calculate the velocity of the drag gesture"""
current_time = GLib.get_monotonic_time() / 1000
if self._last_drag_time > 0:
time_diff = current_time - self._last_drag_time
if time_diff > 0:
distance_diff = current_x - self._drag_start_x - self._current_offset
self._drag_velocity = abs(distance_diff / time_diff)
self._last_drag_time = current_time
def _on_animation_complete(self, is_hiding=False):
@@ -523,109 +435,6 @@ class NotificationRevealer(SlideRevealer):
timeout_duration = 80 if self._swipe_in_progress else (self.duration + 30)
GLib.timeout_add(timeout_duration, lambda: self._on_animation_complete(True))
def _on_button_press(self, _widget, event):
if event.button == 1:
self._drag_start_x = event.x
self._drag_start_y = event.y
self._is_dragging = True
self._swipe_in_progress = False
self._current_offset = 0
self._last_drag_time = GLib.get_monotonic_time() / 1000
self._drag_velocity = 0
# Stop any ongoing animations
if self._spring_timer_id:
GLib.source_remove(self._spring_timer_id)
self._animation_in_progress = False
return False
def _on_button_release(self, _widget, event):
if event.button == 3: # Right click
try:
if self.parent_window:
self.parent_window.clear_notification_queue()
# Also dismiss current notification
self.notification.close("dismissed-by-user")
except:
pass # Ignore errors
return True
elif self._is_dragging and event.button == 1:
self._is_dragging = False
# Calculate final swipe metrics
dx = event.x - self._drag_start_x
dy = abs(event.y - self._drag_start_y)
# Calculate dismiss threshold based on notification width
dismiss_distance = NOTIFICATION_WIDTH * self._dismiss_threshold
# Determine if we should dismiss or spring back
should_dismiss = (
(dx > dismiss_distance and dy < 60) or # Dragged far enough
(dx > 30 and self._drag_velocity > self._swipe_velocity_threshold and dy < 60) # Fast swipe
)
if should_dismiss:
try:
self._swipe_in_progress = True
# For fast dismissal, if already dragged far enough, close immediately
if dx > NOTIFICATION_WIDTH * 0.6:
# Skip animation and close immediately for very large swipes
self.notification.close("dismissed-by-user")
else:
# Animate the dismiss for smaller swipes
self._animate_dismiss(self._current_offset)
logger.debug(f"Notification dismissed by swipe: dx={dx}, velocity={self._drag_velocity}")
except Exception as e:
logger.error(f"Error dismissing notification by swipe: {e}")
else:
# Spring back to original position
if abs(self._current_offset) > 5: # Only animate if there's noticeable displacement
self._animate_spring_back(self._current_offset, 0)
else:
self._apply_transform(0, 1.0, 1.0)
self._current_offset = 0
return False
def _on_motion(self, _widget, event):
if self._is_dragging and not self._animation_in_progress:
# Calculate current swipe distance
dx = event.x - self._drag_start_x
dy = abs(event.y - self._drag_start_y)
# Only respond to primarily horizontal gestures
if dy < 60: # Vertical tolerance
# Calculate velocity for smooth interaction
self._calculate_drag_velocity(event.x)
# Apply real-time transform - only allow rightward movement
if dx > 0:
self._current_offset = dx
# Calculate visual feedback based on drag distance
max_offset = NOTIFICATION_WIDTH * 0.8
offset_ratio = min(1.0, dx / max_offset)
# Apply diminishing returns for large swipes
adjusted_offset = dx * (1.0 - offset_ratio * 0.3)
# Calculate opacity and scale
opacity = 1.0 - (offset_ratio * 0.4) # Fade as it's dragged
scale = 1.0 - (offset_ratio * 0.1) # Slight scale down
self._apply_transform(adjusted_offset, opacity, scale)
# Visual indication of dismiss threshold
if dx > NOTIFICATION_WIDTH * self._dismiss_threshold:
# Could add visual cue here (like changing color)
pass
else:
# Reset to original position if dragging left
self._current_offset = 0
self._apply_transform(0, 1.0, 1.0)
return False
def destroy(self):
# Clean up CSS provider and timers
if self._spring_timer_id:
+9 -4
View File
@@ -15,7 +15,7 @@ class BluetoothIndicator(Box):
self.bluetooth = BluetoothClient()
self.bt_icon = Svg(
name="bt-icon",
size=23,
size=18,
svg_file=get_relative_path(
"../../../config/assets/icons/applets/bluetooth-clear.svg"
),
@@ -49,7 +49,12 @@ class BluetoothIndicator(Box):
"../../../config/assets/icons/applets/bluetooth-clear.svg"
)
)
if len(connected_devices) == 1:
if len(connected_devices) >= 1:
self.bt_icon.set_from_file(
get_relative_path(
"../../../config/assets/icons/applets/bluetooth-paired.svg"
)
)
device = connected_devices[0]
tooltip = f"Connected to {device.alias}"
if device.battery_percentage > 0:
@@ -111,7 +116,7 @@ class NetworkIndicator(Box):
self.network_icon = Svg(
name="network-icon",
size=25,
size=18,
svg_file=get_relative_path(
"../../../config/assets/icons/applets/wifi-clear.svg"
),
@@ -236,7 +241,7 @@ class BatteryIndicator(Box):
self.battery_icon = Svg(
name="battery-icon",
size=22,
size=23,
svg_file=get_relative_path(
"../../../config/assets/icons/battery/battery-100.svg"
),
+2 -2
View File
@@ -41,7 +41,7 @@ class Panel(Window):
self.imac = Button(
name="panel-button",
child=Svg(
size=23,
size=21,
svg_file=get_relative_path("../../config/assets/icons/misc/logo.svg"),
),
on_clicked=lambda *_: self.menubar.show_system_dropdown(self.imac),
@@ -98,7 +98,7 @@ class Panel(Window):
name="panel-button",
on_clicked=lambda *_: self.search_apps(),
child=Svg(
size=22,
size=18,
svg_file=get_relative_path("../../config/assets/icons/misc/search.svg"),
),
)
+542
View File
@@ -0,0 +1,542 @@
import psutil
from fabric.widgets.box import Box
from fabric.widgets.label import Label
from fabric.widgets.overlay import Overlay
from fabric.widgets.datetime import DateTime
from fabric.widgets.circularprogressbar import CircularProgressBar
from widgets.wayland import WaylandWindow as Window
from fabric.utils import invoke_repeater
import requests
import urllib.parse
import datetime
from gi.repository import GLib
from concurrent.futures import ThreadPoolExecutor
import time
import config.data as data
from config.data import load_config
import subprocess
executor = ThreadPoolExecutor(max_workers=4)
config = load_config()
def margin():
return (
data.DOCK_ICON_SIZE + 10
if not data.DOCK_ALWAYS_OCCLUDED and data.DOCK_ENABLED
else 0
)
def get_location():
"""Fetch location from config file or IP API asynchronously."""
for attempt in range(5):
try:
response = requests.get("https://ipinfo.io/json", timeout=3)
if response.status_code == 200:
return response.json().get("city", "").replace(" ", "")
except requests.RequestException as e:
print(f"Error getting location: {e}")
if attempt < 4:
time.sleep(10)
else:
return ""
def get_location_async(callback):
"""Fetch location asynchronously to prevent UI freeze."""
executor.submit(lambda: GLib.idle_add(callback, get_location()))
def get_weather(callback):
"""Fetch weather data asynchronously and update UI."""
def fetch_weather():
location = get_location()
if not location:
return GLib.idle_add(callback, None)
encoded_location = urllib.parse.quote(location)
url = f"https://wttr.in/{encoded_location}?format=j1"
urlemoji = f"https://wttr.in/{encoded_location}?format=%c"
for attempt in range(5):
try:
response = requests.get(urlemoji, timeout=3)
responseinfo = requests.get(url, timeout=3).json()
if response.status_code == 200:
temp_unit = "C"
temp = (
responseinfo["current_condition"][0][f"temp_{temp_unit}"] + "°"
)
condition = responseinfo["current_condition"][0]["weatherDesc"][0][
"value"
]
maxtemp = responseinfo["weather"][0]["maxtempC"] + "°"
mintemp = responseinfo["weather"][0]["mintempC"] + "°"
location = responseinfo["nearest_area"][0]["areaName"][0]["value"]
emoji = response.text.strip()
GLib.idle_add(
callback,
[
emoji,
temp,
condition,
location,
maxtemp,
mintemp,
],
)
return
except requests.RequestException as e:
print(f"Error fetching weather (attempt {attempt + 1}): {e}")
if attempt < 4:
time.sleep(10)
else:
GLib.idle_add(callback, None)
return
executor.submit(fetch_weather)
def update_weather(widget):
def fetch_and_update():
get_weather(lambda weather_info: update_widget(widget, weather_info))
return True
GLib.timeout_add_seconds(600, fetch_and_update)
fetch_and_update()
def update_widget(widget, weather_info):
if weather_info:
widget.weatherinfo = weather_info
widget.update_labels(weather_info)
class Sysinfo(Box):
@staticmethod
def bake_progress_bar(name: str = "progress-bar", size: int = 45, **kwargs):
return CircularProgressBar(
name=name,
start_angle=180,
end_angle=540,
min_value=0,
max_value=100,
size=size,
**kwargs,
)
@staticmethod
def bake_progress_icon(**kwargs):
return Label(**kwargs).build().add_style_class("progress-icon").unwrap()
def __init__(self, **kwargs):
super().__init__(
layer="bottom",
title="sysinfo",
name="sysinfo",
visible=False,
all_visible=False,
**kwargs,
)
self.cpu_progress = self.bake_progress_bar()
self.ram_progress = self.bake_progress_bar()
self.bat_circular = self.bake_progress_bar().build().set_value(42).unwrap()
self.progress_container = Box(
name="progress-bar-container",
spacing=12,
children=[
Box(
children=[
Overlay(
child=self.cpu_progress,
tooltip_text="",
overlays=[
self.bake_progress_icon(
label="",
name="progress-icon-cpu",
)
],
),
],
),
Box(
children=[
Overlay(
child=self.ram_progress,
tooltip_text="",
overlays=[
self.bake_progress_icon(
name="progress-icon-ram",
label="󰘚",
)
],
)
]
),
Box(
children=[
Overlay(
child=self.bat_circular,
tooltip_text="",
overlays=[
self.bake_progress_icon(
label="󱊣",
name="progress-icon-bat",
)
],
),
],
),
],
)
self.update_status()
invoke_repeater(1000, self.update_status)
self.add(
Box(
name="progress-bar-container-main",
orientation="v",
spacing=24,
children=[self.progress_container],
),
)
self.show_all()
def update_status(self):
"""Update system info asynchronously to prevent UI lag."""
def update():
cpu = psutil.cpu_percent()
ram = psutil.virtual_memory().percent
battery = (
psutil.sensors_battery().percent if psutil.sensors_battery() else 80
)
GLib.idle_add(self.cpu_progress.set_value, cpu)
GLib.idle_add(self.ram_progress.set_value, ram)
GLib.idle_add(self.bat_circular.set_value, battery)
GLib.idle_add(self.cpu_progress.set_tooltip_text, f"{str(round(cpu))}%")
GLib.idle_add(self.ram_progress.set_tooltip_text, f"{str(round(ram))}%")
GLib.idle_add(self.bat_circular.set_tooltip_text, f"{str(round(battery))}%")
executor.submit(update)
return True
def fetch_quote(callback):
"""Fetch quotes asynchronously."""
def fetch():
quotes_type = "stoic"
url = (
"https://stoic-quotes.com/api/quote"
if quotes_type == "stoic"
else "https://zenquotes.io/api/random"
)
for attempt in range(5):
try:
response = requests.get(url, timeout=3)
response.raise_for_status()
respdata = response.json()
quote = (
f"{respdata[0]['q']} - {respdata[0]['a']}"
if quotes_type == "zen"
else f"{respdata['text']} - {respdata['author']}"
)
break
except requests.RequestException as e:
print(f"Error fetching quote: {e}")
if attempt < 4:
time.sleep(10)
else:
try:
result = subprocess.run(
["hyprctl", "splash"],
capture_output=True,
text=True,
check=True,
)
quote = result.stdout.strip() + " - Team Hyprland"
except subprocess.CalledProcessError as e:
print(f"Error fetching quote from hyprctl: {e}")
quote = "I learn from the mistakes of people who take my advice - Trix"
GLib.idle_add(callback, quote)
executor.submit(fetch)
def fetch_quote_async(callback):
GLib.idle_add(lambda: fetch_quote(callback))
class QuoteWidget(Label):
def __init__(self, **kwargs):
super().__init__(
name="quote",
label="",
anchor="center",
h_align="center",
v_align="center",
h_expand=True,
justification="center",
v_expand=True,
visible=False,
)
fetch_quote_async(self.update_label)
def update_label(self, quote):
"""Update quote asynchronously."""
max_width = 150 # Set the maximum width for the quote
if len(quote) > max_width:
words = quote.split()
line1, line2 = "", ""
for word in words:
if len(line1) + len(word) + 1 <= max_width:
line1 += word + " "
else:
line2 += word + " "
quote = line1.strip() + "\n" + line2.strip()
self.set_label(quote)
self.set_visible(True)
class ActivationMainText(Label):
def __init__(self, **kwargs):
super().__init__(
name="activation-main-text",
label="",
anchor="bottom right",
justification="left",
v_align="start",
h_align="start",
h_expand=True,
v_expand=True,
visible=False,
)
self.set_label("Activate Linux")
class ActivationSubText(Label):
def __init__(self, **kwargs):
super().__init__(
name="activation-sub-text",
label="",
anchor="bottom right",
justification="left",
v_align="start",
h_align="start",
h_expand=True,
v_expand=True,
visible=False,
)
self.set_label("Go to Settings to activate Linux")
def create_widgets(config):
widgets = []
if config.get("widgets_displaytype_visible", True):
if config.get("widgets_clock_visible", True):
widgets.append(
DateTime(formatters=["%A, %d %B"], interval=10000, name="date")
)
if config.get("widgets_date_visible", True):
widgets.append(DateTime(formatters=["%I:%M %p"], name="clock"))
if config.get("widgets_quote_visible", True):
widgets.append(QuoteWidget())
if config.get("widgets_weatherwid_visible", True):
widgets.append(WeatherWidget())
else:
widgets.append(DateTime(formatters=["%I:%M %p"], name="clock"))
widgets.append(DateTime(formatters=["%A. %d %B"], interval=10000, name="date"))
return widgets
class Weather(Box):
def __init__(self, parent, **kwargs):
super().__init__(
name="weather-widget",
h_expand=True,
v_expand=True,
justification="right",
orientation="v",
all_visible=False,
**kwargs,
)
self.parent = parent
self.city = Label(
name="city", label="New York", justification="right", h_align="start"
)
self.temperature = Label(name="temperature", label="36", h_align="start")
self.condition_em = Label(name="condition-emoji", label="☁️", h_align="start")
self.condition = Label(name="condition", label="Cloudy", h_align="start")
self.feels_like = Label(name="feels-like", label="H:28 L:20", h_align="start")
self.add(self.city)
self.add(self.temperature)
self.add(self.condition_em)
self.add(self.condition)
self.add(self.feels_like)
update_weather(self)
def update_labels(self, weather_info):
if not self.weatherinfo:
return
# Unpack weather info into variables for better readability
emoji, temp, condition, location, maxtemp, mintemp = self.weatherinfo
maxmin = f"H:{maxtemp} L:{mintemp}"
# Store references to deeply nested children to avoid repeated lookups
self.city.set_label(location)
self.feels_like.set_label(maxmin)
self.condition.set_label(condition)
self.temperature.set_label(temp)
self.condition_em.set_label(emoji)
self.parent.set_visible(True)
class WeatherContainer(Box):
def __init__(self, **kwargs):
super().__init__(
orientation="v",
name="box-widget-2",
v_expand=True,
v_align="center",
visible=True,
h_align="center",
children=[
Weather(self),
],
**kwargs,
)
# self.set_style("background-color: rgba(0, 0, 0, 0.5);")
# self.add(Weather())
class Date(Box):
def __init__(self, **kwargs):
super().__init__(
name="date-widget",
h_expand=True,
v_expand=True,
justification="center",
h_align="center",
v_align="start",
orientation="v",
**kwargs,
)
self.top = Box(orientation="h", name="date-top", h_expand=True)
self.dateone = DateTime(formatters=["%a"], interval=10000, name="day")
self.datetwo = DateTime(formatters=["%b"], interval=10000, name="month")
self.datethree = DateTime(formatters=["%-d"], interval=10000, name="date")
self.top.add(self.dateone)
self.top.add(self.datetwo)
self.add(self.top)
self.add(self.datethree)
class Deskwidgets(Window):
def __init__(self, **kwargs):
config = load_config()
super().__init__(
name="desktop",
layer="bottom",
title="desktop-widgets",
orientation="v",
exclusivity="none",
child=[
Window(
anchor="top left",
orientation="h",
layer="bottom",
child=[
Box(
name="desktop-widgets-container",
children=[
Box(
orientation="v",
name="box-widget",
v_expand=True,
v_align="center",
h_align="center",
children=[Date()],
),
WeatherContainer(),
],
),
],
),
Window(
anchor="bottom left",
orientation="h",
layer="bottom",
child=[],
),
],
**kwargs,
)
# else:
#
# class Deskwidgets(Window):
# def __init__(self, **kwargs):
# config = load_config()
# super().__init__(name="desktop", **kwargs)
# desktop_widget = Window(
# layer="bottom",
# anchor="bottom left",
# v_align="start",
# h_align="start",
# h_expand=True,
# v_expand=True,
# justification="left",
# exclusivity="none",
# child=Box(
# orientation="v",
# children=create_widgets(config),
# ),
# all_visible=True,
# )
# if config.get("widgets_activation_visible", True):
# activationnag = Window(
# name="activation",
# anchor="bottom right",
# layer="top",
# justification="left",
# v_align="start",
# h_align="start",
# h_expand=True,
# v_expand=True,
# child=Box(
# orientation="v",
# children=[
# ActivationMainText(),
# ActivationSubText(),
# ],
# ),
# all_visible=True,
# )
# else:
# activationnag = None
#
# else:
#
# class Deskwidgets(Window):
# def __init__(self, **kwargs):
# super().__init__(name="desktop", **kwargs)
# self.set_visible(False)
+3 -1
View File
@@ -5,14 +5,16 @@
margin: 0;
}
#control-center-widgets {
background-color: alpha(#000, 0.3);
background-color: alpha(#fff, 0.09);
box-shadow: inset 0 0 0 1px alpha(#aaa, 0.4);
border: 1px solid alpha(#111, 0.4);
border-radius: 1.25rem;
padding: 0.5rem;
}
/* Widgets */
#wifi-widget,
#bluetooth-widget {
+4 -3
View File
@@ -1,13 +1,14 @@
#launcher {
background-color: alpha(#999, 0.3);
color: #000;
background-color: alpha(#000, 0.3);
padding: 0;
border-radius: 12px;
min-width: 640px;
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.5);
}
#launcher-search{
color: #000;
}
#header_box {
padding: 0px 20px 0 20px;
color: #000;
+4 -1
View File
@@ -14,8 +14,11 @@
margin-top: 10px;
}
#noti-clear-button {
background-color: alpha(#888, 0.09);
}
#noti-clear-button:hover {
background-color: var(--surface-bright);
background-color: alpha(#fff, 0.09);
}
/* Stacked notification group styles */
+3 -3
View File
@@ -1,6 +1,6 @@
#notification {
padding: 16px;
background-color: alpha(#000, 0.3);
background-color: alpha(#fff, 0.03);
/* border: 0.5px solid alpha(#111, 0.4); */
/* box-shadow: */
/* inset 0 0 200px 0 alpha(#111, 0.5), */
@@ -15,14 +15,14 @@
}
#notification-action-buttons button {
background-color: alpha(#000, 0.3);
background-color: alpha(#999, 0.3);
padding: 8px;
border-radius: 20px;
transition: background-color 0.1s ease;
}
#notification-action-buttons button:hover {
background-color: var(--surface-bright);
background-color: alpha(#000, 0.3);
}
#notification-action-buttons button:active {
-1
View File
@@ -16,7 +16,6 @@
}
#panel-button {
border-radius: 8px;
margin: 0 4px 0 4px;
min-width: 20px;
min-height: 20px;