Center TUI copy, shrink window to 520x400 via own app-id windowrule

.desktop now uses --app-id=omatether; install writes a marker-delimited
float/center/size rule block into ~/.config/hypr/windows.conf (backed up
once, removed on uninstall). Dropped udevadm trigger from install — it
wedges an already-connected iPhone (device unconfigured); targeted
usbmuxd restart instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
28allday 2026-07-03 19:44:30 +01:00
parent 52c21e2467
commit c48020f02d
2 changed files with 77 additions and 11 deletions

View file

@ -7,7 +7,7 @@ the phone's Wi-Fi if it's on one, cellular otherwise. Works headless too.
## TUI
Run `omatether.sh` with no arguments (or launch **iPhone Tether** from Walker —
it opens as a floating window). The dashboard shows phone / tether / route
it opens as a small floating window). The dashboard shows phone / tether / route
state live and offers only the actions that make sense right now:
```

View file

@ -12,6 +12,7 @@ set -euo pipefail
NETFILE="/etc/systemd/network/10-iphone-tether.network"
DESKTOP_FILE="$HOME/.local/share/applications/omatether.desktop"
WINDOWS_CONF="$HOME/.config/hypr/windows.conf"
# Route metrics: Omarchy ships ethernet=100, wifi=600, wwan=700.
METRIC_FALLBACK=750 # tether used only when nothing better is up (default)
@ -110,6 +111,31 @@ reload_networkd() {
fi
}
# Small centered floating window for the TUI (user-level Hyprland rule;
# remove-then-append so re-installs stay idempotent).
install_windowrules() {
[[ -f $WINDOWS_CONF ]] || return 0 # not a Hyprland/Omarchy box — skip
if ! grep -q 'omatether windowrules begin' "$WINDOWS_CONF"; then
cp "$WINDOWS_CONF" "$WINDOWS_CONF.bak.$(date +%s)"
fi
sed -i '/>>> omatether windowrules begin/,/<<< omatether windowrules end/d' "$WINDOWS_CONF"
cat >> "$WINDOWS_CONF" <<'EOF'
# >>> omatether windowrules begin
# omatether — small floating window, centered.
windowrule = float on, match:class ^(omatether)$
windowrule = center on, match:class ^(omatether)$
windowrule = size 520 400, match:class ^(omatether)$
# <<< omatether windowrules end
EOF
hyprctl reload >/dev/null 2>&1 || true
}
remove_windowrules() {
[[ -f $WINDOWS_CONF ]] || return 0
sed -i '/>>> omatether windowrules begin/,/<<< omatether windowrules end/d' "$WINDOWS_CONF"
hyprctl reload >/dev/null 2>&1 || true
}
# --------------------------------------------------------- CLI commands ----
cmd_install() {
@ -121,7 +147,8 @@ cmd_install() {
reload_networkd
ok "networkd profile written: $NETFILE (fallback priority, metric $METRIC_FALLBACK)"
# Floating TUI launcher for Walker (Omarchy TUI.float pattern).
# Floating TUI launcher for Walker. Uses a dedicated app-id (rather than
# Omarchy's generic TUI.float) so our own windowrule can size it smaller.
local self
self=$(realpath "$0")
mkdir -p "$(dirname "$DESKTOP_FILE")"
@ -129,17 +156,22 @@ cmd_install() {
[Desktop Entry]
Name=iPhone Tether
Comment=Use an iPhone's internet over USB
Exec=xdg-terminal-exec --app-id=TUI.float -e $self
Exec=xdg-terminal-exec --app-id=omatether -e $self
Icon=phone
Terminal=false
Type=Application
Categories=Network;
EOF
systemctl --user restart elephant.service 2>/dev/null || true
ok "Walker launcher installed: 'iPhone Tether' (floating window)"
install_windowrules
ok "Walker launcher installed: 'iPhone Tether' (small floating window)"
# Nudge udev in case the phone was already plugged in before install.
as_root udevadm trigger -s usb --action=add 2>/dev/null || true
# If the phone was plugged in before usbmuxd existed it won't be seen yet;
# restart usbmuxd to rescan. (Do NOT `udevadm trigger` — re-firing add
# events on a connected iPhone wedges it: "device unconfigured".)
if phone_on_usb && ! phone_visible; then
revive_usbmuxd
fi
say ""
say "Run '$0' (no arguments) for the TUI, or '$0 pair' to pair now."
@ -251,9 +283,10 @@ cmd_priority() {
cmd_uninstall() {
as_root rm -f "$NETFILE"
rm -f "$DESKTOP_FILE"
remove_windowrules
as_root networkctl reload
systemctl --user restart elephant.service 2>/dev/null || true
ok "Removed $NETFILE and the Walker launcher (usbmuxd/libimobiledevice left installed)"
ok "Removed $NETFILE, the Walker launcher and windowrules (usbmuxd/libimobiledevice left installed)"
}
# ----------------------------------------------------------------- TUI -----
@ -272,9 +305,29 @@ poll_terminal_size() {
done
}
# Visible length of a string (ANSI codes stripped; multibyte-aware).
vis_len() {
local s
s=$(printf '%s' "$1" | sed 's/\x1b\[[0-9;]*m//g')
printf '%s' "${#s}"
}
# Print a line horizontally centered in the terminal. Uses $TW (measured
# once per redraw) — tput inside redirected loops can misread the width.
center_line() {
local pad
pad=$(( (${TW:-80} - $(vis_len "$1")) / 2 ))
(( pad < 0 )) && pad=0
printf '%*s%s\n' "$pad" '' "$1"
}
tui_header() {
gum style --border rounded --padding "0 2" --margin "0 0 1 0" \
--border-foreground 212 --bold " OMATETHER" "${DIM}iPhone USB internet${RST}"
local line
while IFS= read -r line; do
center_line "$line"
done < <(gum style --border rounded --padding "0 2" --align center \
--border-foreground 212 --bold " OMATETHER" "${DIM}iPhone USB internet${RST}")
echo
}
tui_connect() {
@ -340,6 +393,7 @@ cmd_tui() {
poll_terminal_size
while true; do
TW=$(tput cols 2>/dev/null || echo 80)
clear
tui_header
@ -382,7 +436,10 @@ cmd_tui() {
uplink_line="${RED}󰈂${RST} No internet route"
fi
printf '%s\n%s\n%s\n\n' "$phone_line" "$tether_line" "$uplink_line"
center_line "$phone_line"
center_line "$tether_line"
center_line "$uplink_line"
echo
# --- context-aware menu ---
local -a menu=()
@ -398,8 +455,17 @@ cmd_tui() {
fi
menu+=("Status (full check)" "Refresh" "Quit")
# Center the menu as a block: pad every label by a common offset
# (2 extra cols account for gum's cursor prefix).
local maxlen=0 mpad m
for m in "${menu[@]}"; do (( ${#m} > maxlen )) && maxlen=${#m}; done
mpad=$(( (TW - maxlen) / 2 - 2 )); (( mpad < 0 )) && mpad=0
local -a pmenu=()
for m in "${menu[@]}"; do pmenu+=("$(printf '%*s%s' "$mpad" '' "$m")"); done
local choice
choice=$(gum choose --header "What do you want to do?" "${menu[@]}") || break
choice=$(gum choose --header "$(printf '%*s%s' "$((mpad + 2))" '' 'What do you want to do?')" "${pmenu[@]}") || break
choice=${choice#"${choice%%[![:space:]]*}"} # trim the centering pad
case $choice in
"Install tethering support") cmd_install; gum input --placeholder "Press Enter…" >/dev/null || true ;;
"Connect phone") tui_connect ;;