Fedora installer, cleanup and screenshots

- install.sh rewritten for Fedora: dry-run, --check, backups, oh-my-zsh, lazygit, swappy
- outputs-setup.sh (monitor layout for new hardware) and doctor.sh (health check)
- screenshot.sh: region / full / window / scroll / last / edit (swappy), saved and copied
- remove waybar, swaync, dunst, rofi and their helper scripts, wallpaper picker, mirror.sh
- wallpapers handled by DMS; keep only the favourite one
- 00-session.conf for portals; swayfx-only layer rules split into 21-dms-effects.conf

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-28 11:01:30 +05:00
co-authored by Claude Sonnet 5.5
parent 1590ccae69
commit 9571b755f8
39 changed files with 438 additions and 840 deletions
-44
View File
@@ -1,44 +0,0 @@
#!/usr/bin/env bash
# Bluetooth menu (rofi): power, connect/disconnect known devices, scan and pair new ones.
THEME=~/.config/rofi/catppuccin.rasi
menu() { rofi -dmenu -i -p "$1" -theme "$THEME" "${@:2}"; }
if ! bluetoothctl show | grep -q "Powered: yes"; then
choice=$(printf '%s\n' "Включить Bluetooth" | menu "Bluetooth") || exit 0
[[ $choice == "Включить Bluetooth" ]] && bluetoothctl power on >/dev/null && notify-send "Bluetooth" "Включён"
exit 0
fi
build() {
local list="" mac name mark
while read -r _ mac name; do
[[ -z $mac ]] && continue
mark="○"; bluetoothctl info "$mac" | grep -q "Connected: yes" && mark="●"
list+="$mark $name [$mac]"$'\n'
done < <(bluetoothctl devices)
printf '%s' "$list"
}
choice=$(printf '%s%s\n%s\n' "$(build)" "Найти новые устройства" "Выключить Bluetooth" | sed '/^$/d' | menu "Bluetooth") || exit 0
[[ -z $choice ]] && exit 0
case $choice in
"Выключить Bluetooth") bluetoothctl power off >/dev/null; notify-send "Bluetooth" "Выключен"; exit 0 ;;
"Найти новые устройства")
notify-send "Bluetooth" "Поиск устройств (8 с)…"
bluetoothctl --timeout 8 scan on >/dev/null 2>&1
choice=$(build | menu "Bluetooth: найденные") || exit 0
[[ -z $choice ]] && exit 0
mac=${choice##*[}; mac=${mac%]}
bluetoothctl pair "$mac" >/dev/null 2>&1; bluetoothctl trust "$mac" >/dev/null 2>&1
bluetoothctl connect "$mac" >/dev/null 2>&1 && notify-send "Bluetooth" "Подключено" || notify-send -u critical "Bluetooth" "Не удалось подключиться"
exit 0 ;;
esac
mac=${choice##*[}; mac=${mac%]}
name=${choice:2}; name=${name% [*}
if [[ ${choice:0:1} == "●" ]]; then
bluetoothctl disconnect "$mac" >/dev/null && notify-send "Bluetooth" "Отключено: $name"
else
bluetoothctl connect "$mac" >/dev/null 2>&1 && notify-send "Bluetooth" "Подключено: $name" || notify-send -u critical "Bluetooth" "Не удалось подключиться: $name"
fi
+2 -3
View File
@@ -1,6 +1,5 @@
#!/bin/bash
# Shows all sway keybindings in rofi
# Shows all sway keybindings in the DMS picker (type to filter, Esc to close)
cat ~/.config/sway/config ~/.config/sway/config.d/*.conf | grep -E '^\s*bindsym' | grep -v -- '--locked' \
| sed -E 's/^\s*bindsym\s+//; s/(--[a-z-]+(=[^ ]+)?\s+)+//; s/\$mod/Super/g; s/^(\S+)\s+/\1\t→ /' \
| column -t -s $'\t' | rofi -dmenu -i -p "Keys" -theme ~/.config/rofi/catppuccin.rasi \
-theme-str 'window {width: 900px;} listview {lines: 14;} entry {placeholder: "Filter...";}' >/dev/null
| column -t -s $'\t' | dms dmenu >/dev/null
+1 -13
View File
@@ -16,22 +16,10 @@ set $right l
# Your preferred terminal emulator
# Recommends: foot
set $term kitty
# Your preferred application launcher
# Note: pass the final command to swaymsg so that the resulting window can be opened
# on the original workspace that the command was run on.
# Recommends: rofi-wayland
set $rofi_cmd rofi -theme ~/.config/rofi/catppuccin.rasi \
-terminal '$term'
# Shows a combined list of the applications with desktop files and
# executables from PATH.
# TODO: add window with the next release of rofi-wayland
set $menu $rofi_cmd -show combi -combi-modes drun#run -modes combi
### Output configuration
#
# Default wallpaper (more resolutions are available in /usr/share/backgrounds/sway/)
# Requires: desktop-backgrounds-compat, swaybg, jxl-pixbuf-loader
output * bg /usr/share/backgrounds/default.jxl fill
# Wallpaper is handled by DankMaterialShell (Settings > Wallpaper), not by sway.
#
# Example configuration:
#
+5
View File
@@ -0,0 +1,5 @@
# Session plumbing so portals (screen sharing, file dialogs, dark mode) and D-Bus activated apps work on any distro.
# Fedora's sway-systemd already does the same; running it twice is harmless.
exec_always dbus-update-activation-environment --systemd WAYLAND_DISPLAY DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP XDG_SESSION_TYPE
exec systemctl --user import-environment WAYLAND_DISPLAY DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP XDG_SESSION_TYPE
exec systemctl --user start sway-session.target
+1 -4
View File
@@ -28,7 +28,6 @@ client.placeholder $base $base $text $base $base
client.background $base
# Autostart
exec_always sh -c 'pkill -x dunst; pkill -x swaync; true'
exec_always sh -c 'pkill -x nm-applet; exec nm-applet --indicator'
bindsym --to-code $mod+Shift+x exec ~/.config/sway/lock.sh
@@ -45,12 +44,10 @@ input type:touchpad {
# Window rules
for_window [app_id="pavucontrol|nm-connection-editor|blueman-manager"] floating enable, resize set 700 500, border pixel 2
for_window [window_role="pop-up"] floating enable
for_window [app_id="rofi"] border none
titlebar_padding 10 4
focus_follows_mouse no
workspace_auto_back_and_forth yes
bindsym --to-code $mod+Shift+p exec dms ipc call powermenu toggle
# Wallpaper + idle/lock
output * bg ~/Pictures/wallpapers/current fill
# Idle / lock
exec_always ~/.config/sway/idle.sh
+1 -6
View File
@@ -29,12 +29,7 @@ dim_inactive_colors.urgent #ff5c5c
# Thin outline instead of fat border -> cleaner look
titlebar_separator disable
# Frosted glass for layers
layer_effects "waybar" blur enable; blur_ignore_transparent enable; corner_radius 14; shadows enable
layer_effects "rofi" blur enable; blur_ignore_transparent enable; corner_radius 20; shadows enable
layer_effects "notifications" blur enable; blur_ignore_transparent enable; corner_radius 14; shadows enable
layer_effects "swaync-control-center" blur enable; blur_ignore_transparent enable; corner_radius 20; shadows enable
layer_effects "swaync-notification-window" blur enable; blur_ignore_transparent enable; corner_radius 14; shadows enable
# Frosted glass for sway's own layers (DMS layers: 21-dms-effects.conf)
layer_effects "swaynag" blur enable; blur_ignore_transparent enable; corner_radius 12
# Translucent terminals, glass shows through
@@ -0,0 +1,8 @@
# SwayFX blur for DMS surfaces (layer names: swaymsg -t get_outputs -r | jq '.[].layer_shell_surfaces[].namespace').
# Only blur: DMS surfaces are bigger than what is drawn, so shadows / corner_radius here would paint
# a glow and rounded corners around the whole (often full-screen) layer.
# SwayFX-only: install.sh drops this file when plain sway is used.
layer_effects "dms:bar" blur enable; blur_ignore_transparent enable
layer_effects "dms:notification-popup" blur enable; blur_ignore_transparent enable
layer_effects "dms:osd" blur enable; blur_ignore_transparent enable
layer_effects "dms:dock" blur enable; blur_ignore_transparent enable
+8 -8
View File
@@ -15,20 +15,20 @@ bindsym --to-code $mod+Ctrl+Left workspace prev_on_output
bindsym --to-code $mod+Shift+f floating toggle, resize set 1000 600, move position center
bindsym --to-code $mod+c exec swaymsg [con_id=__focused__] move position center
# Screenshots: area -> clipboard, area -> file
bindsym --to-code Shift+Print exec ~/.config/sway/screenshot.sh clip
bindsym --to-code $mod+Print exec ~/.config/sway/screenshot.sh file
# Screenshots (saved to ~/Pictures/Screenshots and copied to the clipboard)
bindsym --to-code Print exec ~/.config/sway/screenshot.sh region
bindsym --to-code $mod+Shift+s exec ~/.config/sway/screenshot.sh region
bindsym --to-code Shift+Print exec ~/.config/sway/screenshot.sh full
bindsym --to-code Ctrl+Print exec ~/.config/sway/screenshot.sh window
bindsym --to-code Alt+Print exec ~/.config/sway/screenshot.sh scroll
bindsym --to-code $mod+Print exec ~/.config/sway/screenshot.sh last
bindsym --to-code Ctrl+Shift+Print exec ~/.config/sway/screenshot.sh edit
# Keep video/browser-video windows undimmed
for_window [app_id="firefox"] inhibit_idle fullscreen
for_window [app_id="mpv"] floating enable, dim_inactive 0
# Mirror internal screen to HDMI/TV on hotplug
exec_always ~/.config/sway/mirror.sh
# Rice helpers
bindsym --to-code $mod+Shift+w exec ~/.config/sway/wallpaper.sh
bindsym --to-code $mod+Shift+s exec ~/.config/sway/screenshot-menu.sh
bindsym --to-code $mod+F1 exec ~/.config/sway/cheatsheet.sh
# Performance mode: toggle blur + shadows
bindsym --to-code $mod+Shift+b blur toggle; shadows toggle
-4
View File
@@ -1,4 +0,0 @@
# Waybar (replaces sway-config-fedora's 90-bar.conf, which isn't installed with swayfx)
bar {
swaybar_command waybar
}
-9
View File
@@ -4,15 +4,6 @@ exec_always sh -c 'pgrep -x dms >/dev/null || exec dms run'
# Hotkeys: $mod+d launcher, $mod+n control center, $mod+Shift+n notifications, $mod+Shift+p power menu (set in config / config.d)
bindsym --to-code $mod+Shift+v exec dms ipc call clipboard toggle
# SwayFX blur for DMS surfaces (layer names: swaymsg -t get_outputs -r | jq '.[].layer_shell_surfaces[].namespace').
# Only blur: DMS surfaces are bigger than what is drawn, so shadows / corner_radius here would paint
# a glow and rounded corners around the whole (often full-screen) layer.
layer_effects "dms:bar" blur enable; blur_ignore_transparent enable
layer_effects "dms:notification-popup" blur enable; blur_ignore_transparent enable
layer_effects "dms:osd" blur enable; blur_ignore_transparent enable
layer_effects "dms:dock" blur enable; blur_ignore_transparent enable
# Media keys (work on the lock screen too); DMS shows the OSD
bindsym --locked XF86AudioRaiseVolume exec dms ipc call audio increment 5
bindsym --locked XF86AudioLowerVolume exec dms ipc call audio decrement 5
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env bash
# Health check for the sway-rising setup. Prints OK / WARN / FAIL per item. Exit code = number of FAILs.
CFG=${XDG_CONFIG_HOME:-$HOME/.config}
fails=0
ok() { printf ' \033[32mOK\033[0m %s\n' "$*"; }
warn() { printf ' \033[33mWARN\033[0m %s\n' "$*"; }
bad() { printf ' \033[31mFAIL\033[0m %s\n' "$*"; fails=$((fails+1)); }
have() { command -v "$1" >/dev/null 2>&1; }
section() { printf '\n\033[1m%s\033[0m\n' "$*"; }
section "Compositor"
if have sway; then
v=$(sway --version 2>/dev/null | head -1); ok "$v"
case $v in *swayfx*) ok "SwayFX (blur, shadows, rounded corners available)";; *) warn "plain sway: effects are disabled";; esac
sway -C >/dev/null 2>&1 && ok "sway config is valid" || bad "sway -C reports errors"
else bad "sway / swayfx not installed"; fi
[ -n "${SWAYSOCK:-}" ] && ok "running inside sway" || warn "not inside a sway session (some checks skipped)"
section "Shell (DMS)"
if have dms; then
ok "dms installed"
pgrep -x dms >/dev/null && ok "dms is running" || { [ -n "${SWAYSOCK:-}" ] && bad "dms is not running" || warn "dms not running (not in session)"; }
else bad "dms not installed"; fi
[ -f "$CFG/dms/settings.json" ] && ok "DMS settings present" || warn "no DMS settings yet"
section "Session / portals"
if systemctl --user is-active sway-session.target >/dev/null 2>&1; then ok "sway-session.target active"
else [ -n "${SWAYSOCK:-}" ] && bad "sway-session.target inactive (portals will not start)" || warn "sway-session.target inactive (not in session)"; fi
if [ -n "${SWAYSOCK:-}" ] && have gdbus; then
timeout 10 gdbus call --session --dest org.freedesktop.portal.Desktop --object-path /org/freedesktop/portal/desktop \
--method org.freedesktop.DBus.Properties.Get org.freedesktop.portal.Settings version >/dev/null 2>&1 \
&& ok "xdg-desktop-portal reachable" || bad "xdg-desktop-portal unreachable"
fi
section "Fonts and theme"
fc-list 2>/dev/null | grep -qi "JetBrains Mono" && ok "JetBrains Mono" || bad "JetBrains Mono missing"
fc-list 2>/dev/null | grep -qiE "Font ?Awesome" && ok "Font Awesome" || warn "Font Awesome missing (some icons)"
{ [ -d /usr/share/themes/adw-gtk3-dark ] || [ -d "$HOME/.local/share/themes/adw-gtk3-dark" ]; } && ok "adw-gtk3 theme" || warn "adw-gtk3 theme missing (GTK apps will not follow the palette)"
section "Terminal and shell tools"
for t in kitty zsh tmux git fzf zoxide eza bat fd rg ncdu lazygit; do
have "$t" || { [ "$t" = fd ] && have fdfind; } && ok "$t" || warn "$t missing"
done
[ -d "$HOME/.oh-my-zsh" ] && ok "oh-my-zsh" || warn "oh-my-zsh missing"
[ "$(basename "${SHELL:-}")" = zsh ] && ok "login shell is zsh" || warn "login shell is not zsh (run: chsh -s $(command -v zsh || echo /usr/bin/zsh))"
section "Per-machine config"
[ -f "$CFG/sway/config.d/05-outputs.conf" ] && ok "monitor layout (05-outputs.conf)" || warn "no monitor layout yet: run ~/.config/sway/outputs-setup.sh inside sway"
for t in grim slurp swaylock swayidle brightnessctl playerctl wl-copy rofi; do have "$t" && ok "$t" || warn "$t missing"; done
printf '\n'; [ "$fails" -eq 0 ] && echo "No failures." || echo "$fails failure(s)."
exit "$fails"
-20
View File
@@ -1,20 +0,0 @@
#!/bin/bash
# Mirror the internal display to any external output (sway has no native mirroring).
# Watches output hotplug events; needs wl-mirror.
exec 9>"${XDG_RUNTIME_DIR:-/tmp}/sway-mirror.lock"
flock -n 9 || exit 0
internal=eDP-1
sync() {
pkill -x wl-mirror
for ext in $(swaymsg -t get_outputs -r | jq -r --arg i "$internal" '.[] | select(.active and .name != $i) | .name'); do
wl-mirror --fullscreen-output "$ext" "$internal" &
done
}
sync
swaymsg -t subscribe -m '["output"]' | while read -r _; do
sleep 1
sync
done
+54
View File
@@ -0,0 +1,54 @@
#!/usr/bin/env bash
# Generate ~/.config/sway/config.d/05-outputs.conf from the monitors sway sees right now.
# Laptop panel first (left), the rest follow to the right. Run inside a sway session.
# Usage: outputs-setup.sh [--auto] (--auto: no questions, guess scales)
set -euo pipefail
AUTO=0; [ "${1:-}" = "--auto" ] && AUTO=1
OUT=${XDG_CONFIG_HOME:-$HOME/.config}/sway/config.d/05-outputs.conf
command -v swaymsg >/dev/null && [ -n "${SWAYSOCK:-}" ] || { echo "Run this inside a sway session." >&2; exit 1; }
command -v python3 >/dev/null || { echo "python3 is required." >&2; exit 1; }
mapfile -t ROWS < <(swaymsg -t get_outputs -r | python3 -c '
import json,sys
outs=[o for o in json.load(sys.stdin) if o.get("active") or o.get("power", True)]
# internal panels (eDP/LVDS/DSI) first, then the others by name
outs.sort(key=lambda o:(0 if o["name"].startswith(("eDP","LVDS","DSI")) else 1, o["name"]))
for o in outs:
m=o.get("current_mode") or {}
print(o["name"], m.get("width",0), m.get("height",0), o.get("make","?").replace(" ","_"), o.get("model","?").replace(" ","_"))
')
[ "${#ROWS[@]}" -gt 0 ] || { echo "No outputs found." >&2; exit 1; }
guess_scale() { # name width height
case $1 in
eDP*|LVDS*|DSI*)
if [ "$2" -ge 3000 ]; then echo 2
elif [ "$2" -ge 2400 ]; then echo 1.5
elif [ "$2" -ge 1900 ] && [ "$3" -ge 1200 ]; then echo 1.25
else echo 1; fi ;;
*) echo 1 ;;
esac
}
x=0; body=""
for row in "${ROWS[@]}"; do
read -r name w h make model <<<"$row"
scale=$(guess_scale "$name" "$w" "$h")
if [ "$AUTO" = 0 ]; then
read -r -p "$name ($make $model, ${w}x${h}) scale [$scale]: " ans || ans=""
[ -n "$ans" ] && scale=$ans
fi
body+="output $name position $x 0 scale $scale"$'\n'
x=$(python3 -c "print(int($x + $w / $scale))")
done
mkdir -p "$(dirname "$OUT")"
[ -e "$OUT" ] && cp -a "$OUT" "$OUT.bak"
{
echo "# Monitor layout, generated by outputs-setup.sh (edit freely; re-run to regenerate)"
printf '%s' "$body"
} > "$OUT"
echo "Wrote $OUT:"; cat "$OUT"
swaymsg reload >/dev/null && echo "sway reloaded."
-14
View File
@@ -1,14 +0,0 @@
#!/bin/bash
choice=$(printf '%s\n' ' Area → clipboard' ' Area → file' ' Screen → clipboard' ' Screen → file' \
| rofi -dmenu -i -p "Screenshot" -theme ~/.config/rofi/catppuccin.rasi \
-theme-str 'window {width: 380px;} listview {lines: 4;} entry {enabled: false;}')
dir=$HOME/Pictures/Screenshots; mkdir -p "$dir"
f=$dir/$(date +%F_%H-%M-%S).png
case "$choice" in
*"Area → clipboard") ~/.config/sway/screenshot.sh clip ;;
*"Area → file") ~/.config/sway/screenshot.sh file ;;
*"Screen → clipboard") sleep 0.3; grim - | wl-copy ;;
*"Screen → file") sleep 0.3; grim "$f" ;;
*) exit 0 ;;
esac
notify-send -t 2000 "Screenshot" "Saved"
+29 -9
View File
@@ -1,10 +1,30 @@
#!/bin/sh
# usage: screenshot.sh clip | file
geo=$(slurp) || exit 0
if [ "$1" = file ]; then
dir=$HOME/Pictures/Screenshots
mkdir -p "$dir"
grim -g "$geo" "$dir/$(date +%F_%H-%M-%S).png"
else
grim -g "$geo" - | wl-copy
fi
# Screenshots. Every capture goes to ~/Pictures/Screenshots AND the clipboard, with a notification.
# usage: screenshot.sh region | full | all | window | scroll | last | edit
# region select an area (DMS selector: drag, Enter/Space to confirm, Esc to cancel)
# full the focused monitor all all monitors in one image
# window the focused window last repeat the previous area
# scroll stitch a scrolling area into one tall image (Enter finishes)
# edit select an area and annotate it in swappy (arrows, text, blur; save/copy from there)
dir="$HOME/Pictures/Screenshots"
mkdir -p "$dir"
mode=${1:-region}
case "$mode" in
region|full|all|last|scroll)
exec dms screenshot "$mode" --dir "$dir" ;;
window)
# DMS cannot capture a single window on sway, so use grim on the focused container
geo=$(swaymsg -t get_tree | jq -r '.. | select(.focused? == true) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | head -1)
[ -n "$geo" ] || { notify-send -u low "Screenshot" "No focused window"; exit 1; }
f="$dir/$(date +%F_%H-%M-%S)_window.png"
grim -g "$geo" "$f" && wl-copy < "$f" && notify-send -t 3000 -i "$f" "Screenshot" "Window saved and copied"
;;
edit)
if ! command -v swappy >/dev/null; then
notify-send -u critical "Screenshot" "swappy is not installed: sudo dnf install swappy"; exit 1
fi
dms screenshot region --stdout --no-file --no-clipboard --no-notify | swappy -f -
;;
*) echo "usage: $0 region|full|all|window|scroll|last|edit" >&2; exit 1 ;;
esac
-26
View File
@@ -1,26 +0,0 @@
#!/usr/bin/env bash
# VPN menu (rofi): lists NetworkManager vpn/wireguard connections, click to connect/disconnect.
# Secrets are asked by nm-applet (secret agent).
THEME=~/.config/rofi/catppuccin.rasi
menu() { rofi -dmenu -i -p "$1" -theme "$THEME" "${@:2}"; }
active=$(nmcli -t -e no -f NAME,TYPE connection show --active)
list=""
while IFS= read -r line; do
type=${line##*:}; name=${line%:*}
[[ $type == vpn || $type == wireguard ]] || continue
mark="○"; grep -Fxq "$line" <<<"$active" && mark="●"
list+="$mark $name ($type)"$'\n'
done < <(nmcli -t -e no -f NAME,TYPE connection show)
[[ -z $list ]] && { notify-send "VPN" "Нет настроенных VPN"; exit 0; }
choice=$(printf '%s%s\n' "$list" "Расширенные настройки…" | menu "VPN") || exit 0
[[ -z $choice ]] && exit 0
[[ $choice == "Расширенные настройки…" ]] && exec nm-connection-editor
name=${choice:2}; name=${name% (*}
if [[ ${choice:0:1} == "●" ]]; then
nmcli connection down id "$name" >/dev/null && notify-send "VPN" "Отключено: $name"
else
nmcli connection up id "$name" >/dev/null 2>&1 && notify-send "VPN" "Подключено: $name" || notify-send -u critical "VPN" "Не удалось подключиться: $name"
fi
-14
View File
@@ -1,14 +0,0 @@
#!/bin/bash
# Wallpaper picker with previews. Also used by sway at start (arg: apply).
dir=$HOME/Pictures/wallpapers
cur=$dir/current
if [ "$1" != apply ]; then
pick=$(find "$dir" -maxdepth 1 -type f \( -name '*.jpg' -o -name '*.png' \) | sort | while read -r f; do
printf '%s\0icon\x1f%s\n' "$(basename "$f" | sed 's/\.[^.]*$//')" "$f"
done | rofi -dmenu -i -p "Wallpaper" -show-icons -theme ~/.config/rofi/catppuccin.rasi \
-theme-str 'window {width: 760px;} listview {columns: 3; lines: 2;} element {orientation: vertical; padding: 10px;} element-icon {size: 9em;} element-text {horizontal-align: 0.5;} entry {enabled: false;}')
[ -n "$pick" ] || exit 0
file=$(find "$dir" -maxdepth 1 -type f -name "$pick.*" | head -1)
ln -sf "$file" "$cur"
fi
swaymsg output '*' bg "$cur" fill >/dev/null
-44
View File
@@ -1,44 +0,0 @@
#!/usr/bin/env bash
# Wi-Fi menu (rofi): toggle radio, connect/disconnect, prompt for password on new networks.
THEME=~/.config/rofi/catppuccin.rasi
menu() { rofi -dmenu -i -p "$1" -theme "$THEME" "${@:2}"; }
radio=$(nmcli radio wifi)
if [[ $radio != enabled ]]; then
choice=$(printf '%s\n' "Включить Wi-Fi" | menu "Wi-Fi")
[[ $choice == "Включить Wi-Fi" ]] && nmcli radio wifi on && notify-send "Wi-Fi" "Включён"
exit 0
fi
declare -A seen
list=""
while IFS=: read -r use sig sec ssid; do
[[ -z $ssid || -n ${seen[$ssid]} ]] && continue
seen[$ssid]=1
mark="○"; [[ $use == '*' ]] && mark="●"
lock=""; [[ -n $sec && $sec != "--" ]] && lock=" (защищена)"
list+="$mark $ssid ${sig}%$lock"$'\n'
done < <(nmcli -t -e no -f IN-USE,SIGNAL,SECURITY,SSID dev wifi list --rescan auto | sort -t: -k2 -nr)
choice=$(printf '%s%s\n%s\n' "$list" "Выключить Wi-Fi" "Расширенные настройки…" | sed '/^$/d' | menu "Wi-Fi") || exit 0
[[ -z $choice ]] && exit 0
case $choice in
"Выключить Wi-Fi") nmcli radio wifi off; notify-send "Wi-Fi" "Выключен"; exit 0 ;;
"Расширенные настройки…") exec nm-connection-editor ;;
esac
ssid=${choice:2}; ssid=${ssid%% *}
if [[ ${choice:0:1} == "●" ]]; then
nmcli connection down id "$ssid" >/dev/null && notify-send "Wi-Fi" "Отключено от $ssid"
elif nmcli -t -f NAME connection show | grep -Fxq "$ssid"; then
nmcli connection up id "$ssid" >/dev/null 2>&1 && notify-send "Wi-Fi" "Подключено к $ssid" || notify-send -u critical "Wi-Fi" "Не удалось подключиться к $ssid"
else
if [[ $choice == *"(защищена)"* ]]; then
pw=$(menu "Пароль для $ssid" -password -lines 0) || exit 0
out=$(nmcli dev wifi connect "$ssid" password "$pw" 2>&1)
else
out=$(nmcli dev wifi connect "$ssid" 2>&1)
fi
[[ $? -eq 0 ]] && notify-send "Wi-Fi" "Подключено к $ssid" || notify-send -u critical "Wi-Fi" "Ошибка: $out"
fi