Added space-misson-clock-style timer to eww
This commit is contained in:
@@ -12,25 +12,42 @@
|
||||
color: $foreground;
|
||||
font-family: "Armstrong";
|
||||
font-size: 9pt;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
background-color: rgba(30, 30, 30, 0.7);
|
||||
padding: 10px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
|
||||
&:not(.focused) {
|
||||
border-color: $bg0;
|
||||
}
|
||||
&.focused {
|
||||
border-color: $foreground;
|
||||
}
|
||||
|
||||
// Probably needs to change
|
||||
&.bar {
|
||||
margin: 10px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
&.bottombar {
|
||||
margin: 10px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
&.left-side {
|
||||
margin: 10px;
|
||||
margin-top: 20px;
|
||||
margin-top: 39px;
|
||||
margin-right: 0px;
|
||||
padding-bottom: 26px;
|
||||
margin-bottom: 39px;
|
||||
|
||||
}
|
||||
|
||||
&.right-side {
|
||||
margin: 10px;
|
||||
margin-top: 20px;
|
||||
margin-top: 39px;
|
||||
margin-left: 0px;
|
||||
padding-bottom: 26px;
|
||||
margin-bottom: 39px;
|
||||
}
|
||||
|
||||
&.bg {
|
||||
@@ -73,7 +90,7 @@
|
||||
}
|
||||
|
||||
.gauge-gutter {
|
||||
color: $bg0;
|
||||
color: rgba(30, 30, 30, 0.5);
|
||||
}
|
||||
|
||||
.icon {
|
||||
@@ -81,7 +98,7 @@
|
||||
}
|
||||
|
||||
.invisible {
|
||||
color: $wallpaper;
|
||||
color: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.highlight {
|
||||
@@ -122,7 +139,8 @@
|
||||
// sway module
|
||||
|
||||
.sway--root.sway--vertical {
|
||||
padding-top: 20px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.sway--ws {
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
:anchor "top center")
|
||||
:exclusive true
|
||||
:focusable false
|
||||
:stacking "fg"
|
||||
:stacking "bg"
|
||||
(centerbox :orientation "h"
|
||||
:class "bar root"
|
||||
:class "bar root ${sway--data.visible[group].focused ? 'focused' : ''}"
|
||||
(hostname-leftalign)
|
||||
''
|
||||
(ws-group-rightalign :workspace-group {group})))
|
||||
@@ -31,9 +31,9 @@
|
||||
:anchor "top center")
|
||||
:exclusive true
|
||||
:focusable false
|
||||
:stacking "fg"
|
||||
:stacking "bg"
|
||||
(centerbox :orientation "h"
|
||||
:class "bar root"
|
||||
:class "bar root ${sway--data.visible[group].focused ? 'focused' : ''}"
|
||||
(ws-group-leftalign :workspace-group {group})
|
||||
(hostname-centeralign)
|
||||
(desktop-details-rightalign)))
|
||||
@@ -44,9 +44,9 @@
|
||||
:anchor "top center")
|
||||
:exclusive true
|
||||
:focusable false
|
||||
:stacking "fg"
|
||||
:stacking "bg"
|
||||
(centerbox :orientation "h"
|
||||
:class "bar root"
|
||||
:class "bar root ${sway--data.visible[group].focused ? 'focused' : ''}"
|
||||
(ws-group-leftalign :workspace-group {group})
|
||||
''
|
||||
(hostname-rightalign)))
|
||||
@@ -57,8 +57,14 @@
|
||||
:anchor "${side} center")
|
||||
:exclusive true
|
||||
:focusable false
|
||||
:stacking "fg"
|
||||
(system-sidebar :orientation {side}))
|
||||
:stacking "bg"
|
||||
(centerbox :orientation "v"
|
||||
;; :class "root ${side}-side ${sway--data.visible[group].focused ? 'focused' : ''}"
|
||||
(system-sidebar :group {group}
|
||||
:side {side})
|
||||
""
|
||||
""
|
||||
))
|
||||
|
||||
(defwindow user-sidebar [group side]
|
||||
:geometry (geometry :width "200px"
|
||||
@@ -66,7 +72,7 @@
|
||||
:anchor "${side} center")
|
||||
:exclusive true
|
||||
:focusable false
|
||||
:stacking "fg"
|
||||
:stacking "bg"
|
||||
(user-sidebar :orientation {side}))
|
||||
|
||||
|
||||
@@ -76,9 +82,9 @@
|
||||
:anchor "top center")
|
||||
:exclusive true
|
||||
:focusable false
|
||||
:stacking "fg"
|
||||
:stacking "bg"
|
||||
(centerbox :orientation "h"
|
||||
:class "bar root"
|
||||
:class "laptop bar root ${sway--data.visible[group].focused ? 'focused' : ''}"
|
||||
(hostname-and-workspace-leftalign :workspace-group {group})
|
||||
""
|
||||
(laptop-details-rightalign :battery {battery} )))
|
||||
@@ -89,10 +95,14 @@
|
||||
:anchor "${side} center")
|
||||
:exclusive true
|
||||
:focusable false
|
||||
:stacking "fg"
|
||||
(small-sidebar :orientation {side}
|
||||
:battery {battery}
|
||||
:workspace-group {group}))
|
||||
:stacking "bg"
|
||||
(centerbox :orientation "v"
|
||||
(laptop-sidebar-top :group {group}
|
||||
:side {side})
|
||||
""
|
||||
(laptop-sidebar-bottom :group {group}
|
||||
:side {side}
|
||||
:battery {battery})))
|
||||
|
||||
(defwindow vertical-bottombar [group]
|
||||
:geometry (geometry :width "100%"
|
||||
@@ -100,9 +110,9 @@
|
||||
:anchor "bottom center")
|
||||
:exclusive true
|
||||
:focusable false
|
||||
:stacking "fg"
|
||||
:stacking "bg"
|
||||
(centerbox :orientation "h"
|
||||
:class "bar root"
|
||||
:class "bottombar root ${sway--data.visible[group].focused ? 'focused' : ''}"
|
||||
(date)
|
||||
(big-clock)
|
||||
(horizontal-minigauges-rightalign)))
|
||||
|
||||
@@ -21,6 +21,26 @@
|
||||
(label :text {formattime(clock--data.stamp, "%Y-%m-%d", clock--data.tz)})))
|
||||
|
||||
|
||||
(defwidget mission-clock []
|
||||
(box :class "module text"
|
||||
:spacing 0
|
||||
:orientation "v"
|
||||
:halign "center"
|
||||
:valign "center"
|
||||
:visible {clock--data.timer.active}
|
||||
(box :orientation "h"
|
||||
:space-evenly false
|
||||
:spacing 5
|
||||
:valign "center"
|
||||
:halign "center"
|
||||
(label :text 'T'
|
||||
:class "special")
|
||||
(label :text {clock--data.timer.started ? "+" : "-"}
|
||||
:class {clock--data.timer.started ? "green" : "highlight"})
|
||||
(label :text {clock--data.timer.timer}
|
||||
:class "special"))
|
||||
(label :text '${clock--data.timer.title} ${clock--data.timer.prefix}')))
|
||||
|
||||
(defwidget big-clock []
|
||||
(centerbox :class "bigger nebula"
|
||||
:space-evenly false
|
||||
@@ -46,9 +66,32 @@
|
||||
(label :text {formattime(clock--data.stamp, "%B %d", clock--data.tz)}
|
||||
:class "special"
|
||||
:valign "center")))
|
||||
|
||||
|
||||
|
||||
(defwidget side-mission-clock []
|
||||
(box :class "module text"
|
||||
:space-evenly false
|
||||
:spacing 5
|
||||
:halign "start"
|
||||
:valign "center"
|
||||
:visible {clock--data.timer.active}
|
||||
:width 200
|
||||
:orientation "v"
|
||||
(label :class "big nebula special"
|
||||
:text {clock--data.timer.title})
|
||||
(label :class "nebula"
|
||||
:text {clock--data.timer.prefix})
|
||||
(box :class "nebula"
|
||||
:spacing 5
|
||||
:halign "center"
|
||||
:space-evenly false
|
||||
(label :text "T")
|
||||
(label :class {clock--data.timer.started ? "green" : "highlight"}
|
||||
:text {clock--data.timer.started ? "+" : "-"})
|
||||
|
||||
(label :class "nebula"
|
||||
:text {clock--data.timer.timer}))))
|
||||
|
||||
(defwidget sideclock []
|
||||
(button :onclick "echo -n $(date +%Y-%d-%m) | wl-copy && eww update clock--show=date && sleep 2 && eww update clock--show=clock"
|
||||
:onrightclick "echo -n $(date +%s) | wl-copy && eww update clock--show=unixtime && sleep 2 && eww update clock--show=clock"
|
||||
|
||||
@@ -11,7 +11,7 @@ import time
|
||||
import asyncio
|
||||
from asyncinotify import Inotify, Mask
|
||||
from pathlib import Path
|
||||
from json import dump
|
||||
from json import load, dump
|
||||
|
||||
|
||||
def refresh_tz():
|
||||
@@ -29,7 +29,55 @@ def refresh_tz():
|
||||
return tz, source
|
||||
|
||||
|
||||
def refresh_timer():
|
||||
"""Reload the timer."""
|
||||
|
||||
timer_file = Path("~/.config/eww/timer.json").expanduser()
|
||||
if timer_file.exists() and timer_file.is_file():
|
||||
with timer_file.open("r") as f:
|
||||
return load(f)
|
||||
return None
|
||||
|
||||
|
||||
timezone, source = refresh_tz()
|
||||
timer = refresh_timer()
|
||||
|
||||
|
||||
def format_timer():
|
||||
"""Format the timer delta."""
|
||||
|
||||
if timer is None:
|
||||
return {"active": False, "error": False, "reason": "no timer"}
|
||||
|
||||
startstamp = timer.get("start")
|
||||
if startstamp is None:
|
||||
return {"active": False, "error": True, "reason": "no start"}
|
||||
start = datetime.datetime.fromtimestamp(startstamp)
|
||||
|
||||
now = datetime.datetime.now()
|
||||
if (stopstamp := timer.get("stop")) is not None:
|
||||
stop = datetime.datetime.fromtimestamp(stopstamp)
|
||||
if stop < now:
|
||||
return {"active": False, "error": False, "reason": f"stopped at {stop}"}
|
||||
|
||||
delta_sec = (now - start).total_seconds()
|
||||
started = True
|
||||
if delta_sec < 0:
|
||||
started = False
|
||||
delta = datetime.timedelta(seconds=int(abs(delta_sec)))
|
||||
else:
|
||||
delta = datetime.timedelta(seconds=int(delta_sec))
|
||||
days = delta.days
|
||||
remainder = datetime.timedelta(seconds=delta.total_seconds() - (days * 24 * 3600))
|
||||
|
||||
return {
|
||||
"active": True,
|
||||
"error": False,
|
||||
"prefix": timer.get("prefix", "MET"),
|
||||
"title": timer.get("title", "timer"),
|
||||
"started": started,
|
||||
"timer": f"{days}d {str(remainder)}",
|
||||
}
|
||||
|
||||
|
||||
async def main():
|
||||
@@ -41,6 +89,7 @@ async def main():
|
||||
"stamp": int(datetime.datetime.now().timestamp()),
|
||||
"tz": timezone,
|
||||
"tz-source": source,
|
||||
"timer": format_timer(),
|
||||
},
|
||||
sys.stdout,
|
||||
)
|
||||
@@ -51,15 +100,16 @@ async def main():
|
||||
|
||||
async def monitor():
|
||||
"""Timezone monitor loop."""
|
||||
global timezone, source
|
||||
global timezone, source, timer
|
||||
with Inotify() as inotify:
|
||||
inotify.add_watch(
|
||||
Path("~/.config/eww").expanduser(),
|
||||
Mask.CREATE | Mask.DELETE,
|
||||
Mask.CREATE | Mask.DELETE | Mask.MODIFY,
|
||||
)
|
||||
inotify.add_watch(Path("/etc"), Mask.CREATE | Mask.DELETE)
|
||||
async for event in inotify:
|
||||
timezone, source = refresh_tz()
|
||||
timer = refresh_timer()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -6,11 +6,13 @@ import json
|
||||
import asyncio
|
||||
import sys
|
||||
|
||||
|
||||
PRIORITY_PLAYERS = {"Feishin"}
|
||||
|
||||
# Override the reported album if the URL is in this dict
|
||||
URL_ALBUM_OVERRIDES = {"https://distantworlds3.space/radio/": "Distant Radio"}
|
||||
URL_ALBUM_OVERRIDES = {
|
||||
"https://distantworlds3.space/radio/": "Distant Radio",
|
||||
"https://radio.distantworlds3.space/listen/distant_radio/distantradio.mp3": "Distant Radio",
|
||||
}
|
||||
|
||||
|
||||
class MprisMonitor(Gio.Application):
|
||||
|
||||
@@ -120,12 +120,13 @@ def get_gateways():
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def get_ssid():
|
||||
|
||||
cmd = ['iwgetid', '-r']
|
||||
cmd = ["iwgetid", "-r"]
|
||||
result = run(cmd, stdout=PIPE, stderr=PIPE)
|
||||
if result.returncode == 0:
|
||||
return result.stdout.decode('utf-8').strip()
|
||||
return result.stdout.decode("utf-8").strip()
|
||||
else:
|
||||
return None
|
||||
|
||||
@@ -180,7 +181,7 @@ def get_public_ip():
|
||||
|
||||
def get_default_route():
|
||||
"""Get the default route."""
|
||||
cmd = ["ip", "route", "show", "default"]
|
||||
cmd = ["ip", "route", "get", "1.1.1.1"]
|
||||
result = run(cmd, stdout=PIPE, stderr=PIPE)
|
||||
try:
|
||||
# Get first line (might have multiple gateway routes)
|
||||
@@ -205,6 +206,7 @@ def format_time(time: datetime) -> dict[str, str | int]:
|
||||
"unix": int(time.timestamp()),
|
||||
}
|
||||
|
||||
|
||||
runtime_dir = os.environ.get("XDG_RUNTIME_DIR", "/tmp")
|
||||
|
||||
|
||||
@@ -299,7 +301,7 @@ while True:
|
||||
"wifi": {
|
||||
"ssid": ssid,
|
||||
"connected": wifi_connected,
|
||||
"default": default_route == "wlan0"
|
||||
"default": default_route == "wlan0",
|
||||
},
|
||||
"last_update": format_time(datetime.now()),
|
||||
}
|
||||
|
||||
@@ -1,56 +1,51 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# This script prints the time remaining for the current timer
|
||||
# as stored in the file ~/.timer as a binary unix timestamp.
|
||||
# Produces a mission timer based on the start time stored in the ~/.config/eww/timer.json file.
|
||||
# This file should have an object with three fields: "start", containing the start time as an integer
|
||||
# Unix timestamp in second resolution, "title", containing the title to be presented beneath the timer,
|
||||
# and "prefix", containing a string to render in front of the timer (such as "MET")
|
||||
|
||||
import time
|
||||
import datetime
|
||||
import json
|
||||
import sys
|
||||
import asyncio
|
||||
from asyncinotify import Inotify, Mask
|
||||
from pathlib import Path
|
||||
|
||||
# Get the time stored in the file ~/.timer
|
||||
try:
|
||||
with open("/home/ezri/.timer", "br") as f:
|
||||
timer = f.read()
|
||||
except FileNotFoundError:
|
||||
print("It's Time!", flush=True)
|
||||
exit()
|
||||
|
||||
# Convert the binary unix timestamp to a datetime object
|
||||
timer = datetime.datetime.fromtimestamp(int.from_bytes(timer, "big"))
|
||||
def refresh_timer():
|
||||
"""Reload the timer."""
|
||||
|
||||
while True:
|
||||
# Get the current time
|
||||
now = datetime.datetime.now()
|
||||
timer_file = Path("~/.config/eww/timer.json")
|
||||
if timer_file.exists() and timer_file.is_file():
|
||||
with timer_file.open("r") as f:
|
||||
return json.load(f)
|
||||
return None
|
||||
|
||||
# Calculate the time remaining
|
||||
remaining = timer - now
|
||||
|
||||
# If the timer has already expired, delete the file and exit
|
||||
if remaining.total_seconds() <= 0:
|
||||
import os
|
||||
timer = refresh_timer()
|
||||
|
||||
os.remove("/home/ezri/.timer")
|
||||
print("Timer expired.")
|
||||
|
||||
# Print the time remaining in the format "D days, HH:MM:SS"
|
||||
if remaining.days == 0:
|
||||
print(
|
||||
"{} hours {:02d}:{:02d}".format(
|
||||
remaining.seconds // 3600,
|
||||
remaining.seconds % 3600 // 60,
|
||||
remaining.seconds % 60,
|
||||
),
|
||||
flush=True,
|
||||
)
|
||||
else:
|
||||
print(
|
||||
"{} days, {:02d}:{:02d}:{:02d}".format(
|
||||
remaining.days,
|
||||
remaining.seconds // 3600,
|
||||
remaining.seconds % 3600 // 60,
|
||||
remaining.seconds % 60,
|
||||
),
|
||||
flush=True,
|
||||
)
|
||||
|
||||
# Wait half a second before printing the time again
|
||||
time.sleep(1)
|
||||
async def main():
|
||||
"""Print loop."""
|
||||
asyncio.ensure_future(asyncio.create_task(monitor()))
|
||||
while True:
|
||||
if timer is None:
|
||||
json.dump({"active": False}, sys.stdout)
|
||||
else:
|
||||
start = timer.get("start", 0)
|
||||
now = datetime.datetime.now()
|
||||
if now < start:
|
||||
started = True
|
||||
else:
|
||||
started = False
|
||||
json.dump(
|
||||
{
|
||||
"active": True,
|
||||
"stamp": timer.get("start", 0),
|
||||
"title": timer.get("title", "timer"),
|
||||
"prefix": timer.get("prefix", "MET"),
|
||||
},
|
||||
sys.stdout,
|
||||
)
|
||||
|
||||
5
.config/eww/timer.json
Normal file
5
.config/eww/timer.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"title": "DW3",
|
||||
"prefix": "expedition clock",
|
||||
"start": 1768759200
|
||||
}
|
||||
@@ -6,13 +6,14 @@
|
||||
;; Generic Windows ;;
|
||||
;;; ;;;
|
||||
|
||||
(defwidget system-sidebar [orientation]
|
||||
(defwidget system-sidebar [group side]
|
||||
(box :orientation "v"
|
||||
:valign "start"
|
||||
:space-evenly false
|
||||
:spacing 20
|
||||
:class "root ${orientation}-side"
|
||||
:class "root ${side}-side ${sway--data.visible[group].focused ? 'focused' : ''}"
|
||||
(sideclock)
|
||||
(side-mission-clock)
|
||||
(network-sidebar-details)
|
||||
(system-gauges)
|
||||
(volume-gauges)))
|
||||
@@ -27,23 +28,37 @@
|
||||
(mpris-miniplayer)
|
||||
(volume-gauges)))
|
||||
|
||||
(defwidget small-sidebar [orientation battery workspace-group]
|
||||
(centerbox :orientation "v"
|
||||
:class "root ${orientation}-side"
|
||||
(sway-workspaces-vertical :group {workspace-group})
|
||||
""
|
||||
(box :orientation "v"
|
||||
:valign "end"
|
||||
:space-evenly false
|
||||
:spacing 10
|
||||
|
||||
(system--cpu-gauge-small)
|
||||
(system--memory-gauge-small)
|
||||
(system--swap-gauge-small)
|
||||
(system--gpu-gauge-small)
|
||||
(system--vram-gauge-small)
|
||||
(volume-small-gauge)
|
||||
(system-battery-gauge-small :battery {battery}))))
|
||||
(defwidget minigauges-bottomalign [battery]
|
||||
(box :orientation "v"
|
||||
:valign "end"
|
||||
:space-evenly false
|
||||
:spacing 10
|
||||
(system--cpu-gauge-small)
|
||||
(system--memory-gauge-small)
|
||||
(system--swap-gauge-small)
|
||||
(system--gpu-gauge-small)
|
||||
(system--vram-gauge-small)
|
||||
(volume-small-gauge)
|
||||
(system-battery-gauge-small :battery {battery})))
|
||||
|
||||
|
||||
(defwidget laptop-sidebar-top [group side]
|
||||
(box :orientation "v"
|
||||
:valign "start"
|
||||
:space-evenly false
|
||||
:spacing 10
|
||||
:class "root ${side}-side ${sway--data.visible[group].focused ? 'focused' : ''}"
|
||||
(sway-workspaces-vertical :group {group})))
|
||||
|
||||
(defwidget laptop-sidebar-bottom [group side battery]
|
||||
(box :orientation "v"
|
||||
:valign "start"
|
||||
:space-evenly false
|
||||
:spacing 10
|
||||
:class "root ${side}-side ${sway--data.visible[group].focused ? 'focused' : ''}"
|
||||
(minigauges-bottomalign :battery {battery})))
|
||||
|
||||
|
||||
|
||||
(defwidget ws-group-rightalign [workspace-group]
|
||||
(box :orientation "h"
|
||||
@@ -71,6 +86,7 @@
|
||||
:spacing 20
|
||||
:class "rightbox"
|
||||
(mpris2)
|
||||
(mission-clock)
|
||||
(vpn-network)
|
||||
(network)
|
||||
(wifi)
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
[Unit]
|
||||
Description=AggieTimeD
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStartPre=-/usr/bin/rm /run/user/%U/aggietimed.sock
|
||||
ExecStartPre=/usr/bin/sleep 1
|
||||
ExecStart=/usr/bin/node /usr/bin/aggietimed -d -s /run/user/%U/aggietimed.sock -p echo
|
||||
RestartSec=30
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=sway-session.target
|
||||
@@ -1,10 +0,0 @@
|
||||
[Unit]
|
||||
Description=Socket-activation proxy for alacritty
|
||||
PartOf=graphical-session.target
|
||||
BindsTo=alacritty.service
|
||||
After=alacritty.service
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
ExecStart=/usr/lib/systemd/systemd-socket-proxyd %t/alacritty-direct
|
||||
Slice=session.slice
|
||||
@@ -1,7 +0,0 @@
|
||||
[Unit]
|
||||
Description=Socket activation for alacritty
|
||||
PartOf=graphical-session
|
||||
|
||||
[Socket]
|
||||
ListenStream=%t/alacritty
|
||||
SocketMode=0600
|
||||
@@ -1,11 +0,0 @@
|
||||
[Unit]
|
||||
Description=dunst notification daemon
|
||||
PartOf=sway-session.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=dunst
|
||||
Slice=session.slice
|
||||
|
||||
[Install]
|
||||
WantedBy=sway-session.target
|
||||
@@ -1,7 +0,0 @@
|
||||
[Unit]
|
||||
Description=Hyprland compositor session
|
||||
Documentation=man:systemd.special
|
||||
BindsTo=graphical-session.target
|
||||
Wants=graphical-session-pre.target
|
||||
After=graphical-session-pre.target
|
||||
Wants=sway-session.target
|
||||
2
.config/systemd/user/screens-off.target
Normal file
2
.config/systemd/user/screens-off.target
Normal file
@@ -0,0 +1,2 @@
|
||||
[Unit]
|
||||
Description=Displays are turned off
|
||||
Reference in New Issue
Block a user