nixfiles/home-manager/modules/ezpcusr.nix
2025-09-24 20:58:12 -07:00

576 lines
18 KiB
Nix

inputs: {
config,
lib,
pkgs,
...
}:
with lib; let
cfg = config.ezpcusr;
lockCommand = pkgs.writeShellScript "lock.sh" ''
exec ${pkgs.swaylock}/bin/swaylock -f
'';
in {
options.ezpcusr = {
enable = mkEnableOption "Enable simple PC user config";
uploadScript = mkOption {
type = types.nullOr types.package;
default = null;
description = "A path to a script that takes a path to a file and returns a URL";
};
screenshotsPath = mkOption {
description = "Path to save screenshots in";
default = "$HOME/Media/Screenshots";
type = types.str;
};
screensaver = mkOption {
description = "ezpcusr screensaver";
default = {};
type = types.submodule {
options = {
lockTime = mkOption {
type = types.int;
default = 600;
description = "Time until your screen locks";
};
offTime = mkOption {
type = types.int;
default = 900;
description = "Time until your screen turns off";
};
};
};
};
bluetooth = mkOption {
type = types.bool;
default = false;
description = "If this PC has bluetooth support";
};
battery = mkOption {
type = types.bool;
default = false;
description = "If this PC has a battery";
};
};
config = lib.mkIf cfg.enable {
services.swayidle = {
enable = lib.mkDefault true;
events = [
{
event = "before-sleep";
command = "${pkgs.systemd}/bin/loginctl lock-session";
}
{
event = "lock";
command = "${pkgs.playerctl}/bin/playerctl -a pause; ${lockCommand}";
}
{
event = "unlock";
command = "${pkgs.procps}/bin/pkill -USR1 swaylock";
}
];
timeouts = [
{
timeout = cfg.screensaver.lockTime;
command = "${pkgs.systemd}/bin/loginctl lock-session";
}
{
timeout = cfg.screensaver.offTime;
command = "${pkgs.sway}/bin/swaymsg 'output * dpms off'";
resumeCommand = "${pkgs.sway}/bin/swaymsg 'output * dpms on'";
}
];
};
wayland.windowManager.hyprland = {
enable = false;
systemd.enable = true;
extraConfig = let
swayConfig = config.wayland.windowManager.sway.config;
swayBindings = swayConfig.keybindings;
swayToHyprlandBinding = key: binding: let
splitKey = lib.splitString "+" key;
isMod = m: m == "Mod4" || m == "Shift";
convertMod = m:
if m == "Mod4"
then "SUPER"
else lib.toUpper m;
mods = filter isMod splitKey;
modsStr = "${(lib.concatStringsSep "_" (map convertMod mods))},";
normalKeys = filter (m: isMod m == false) splitKey;
normalKey = lib.elemAt normalKeys 0;
convertedKey = "${modsStr}${normalKey}";
convertDir = dir: lib.elemAt (lib.stringToCharacters dir) 0;
splitBinding = lib.splitString " " binding;
bindingAction = lib.elemAt splitBinding 0;
newBinding =
if bindingAction == "exec"
then "exec, ${lib.concatStringsSep " " (lib.tail splitBinding)}"
else if bindingAction == "workspace"
then let n = lib.last splitBinding; in "workspace, ${n}"
else if bindingAction == "kill"
then "killactive,"
else if bindingAction == "focus"
then let
l = lib.last splitBinding;
in
if l == "mode_toggle"
then "togglefloating,"
else "movefocus,${convertDir l}"
else if bindingAction == "fullscreen"
then "fullscreen,0"
else if bindingAction == "floating"
then "togglefloating,"
else if bindingAction == "move"
then let
splitMove = lib.tail splitBinding;
moveThing = lib.elemAt splitMove 0;
toThing =
if lib.length splitMove >= 3
then lib.elemAt splitMove 2
else null;
in
if toThing == null
then "movewindow,${convertDir moveThing}"
else if moveThing == "container" && toThing == "workspace"
then "movetoworkspacesilent,${lib.last splitMove}"
else null
else null;
in
if newBinding == null
then "# ${key} - ${binding}"
else "bind=${convertedKey}, ${newBinding}";
convertedBindings = lib.concatStringsSep "\n" (lib.mapAttrsToList swayToHyprlandBinding swayBindings);
bindingsStr = "${convertedBindings}\n";
in ''
monitor=,preferred,auto,auto
gestures {
workspace_swipe = on
}
${convertedBindings}
'';
};
wayland.windowManager.sway = {
enable = lib.mkDefault true;
systemd.enable = lib.mkDefault true;
wrapperFeatures.gtk = lib.mkDefault true;
extraConfig = ''
exec keyctl link @u @s
workspace 1
'';
config = {
terminal = lib.mkDefault "${pkgs.foot}/bin/foot";
modifier = lib.mkDefault "Mod4";
keybindings = let
modifier = config.wayland.windowManager.sway.config.modifier;
alphabet = ["Ctrl" "Alt" "Ctrl+Alt"];
genKeyAttrs = move:
lib.listToAttrs (
map
(
n: {
name = "${modifier}${
if move
then "+Shift"
else ""
}+${builtins.elemAt alphabet ((n - 11) / 10)}+${toString (lib.mod n 10)}";
value = "${
if move
then "move container to "
else ""
}workspace number ${toString n}";
}
)
(lib.lists.range 11 (10 * (builtins.length alphabet) + 10))
);
in
lib.mkOptionDefault (
let
volumeUp = "exec ${pkgs.pulseaudio}/bin/pactl set-sink-volume @DEFAULT_SINK@ +5%";
volumeDown = "exec ${pkgs.pulseaudio}/bin/pactl set-sink-volume @DEFAULT_SINK@ -5%";
in
{
"${modifier}+q" = "kill";
"Print" = "exec ${config.services.flameshot.package}/bin/flameshot gui -p=\"${config.services.flameshot.settings.General.savePath}/$(date '+${config.services.flameshot.settings.General.filenamePattern}')\" --raw | ${pkgs.wl-clipboard}/bin/wl-copy -t image/png";
"Shift+Print" = "exec ${pkgs.wl-clipboard}/bin/wl-paste > /tmp/clipup && ${
if cfg.uploadScript != null
then cfg.uploadScript
else ":"
} /tmp/clipup | ${pkgs.wl-clipboard}/bin/wl-copy && ${pkgs.libnotify}/bin/notify-send 'Clipboard uploaded!'";
"${modifier}+c" = "exec ${config.services.clipman.package}/bin/clipman pick -t rofi";
"${modifier}+minus" = volumeDown;
"${modifier}+equal" = volumeUp;
"XF86AudioRaiseVolume" = volumeUp;
"XF86AudioLowerVolume" = volumeDown;
"XF86AudioMute" = "exec ${pkgs.pulseaudio}/bin/pactl set-sink-mute @DEFAULT_SINK@ toggle";
"XF86AudioMicMute" = "exec ${pkgs.pulseaudio}/bin/pactl set-source-mute @DEFAULT_SOURCE@ toggle";
"XF86MonBrightnessDown" = "exec ${pkgs.light}/bin/light -U 10";
"XF86MonBrightnessUp" = "exec ${pkgs.light}/bin/light -A 10";
"${modifier}+semicolon" = "exec ${pkgs.light}/bin/light -U 10";
"${modifier}+apostrophe" = "exec ${pkgs.light}/bin/light -A 10";
# Previous/next but change the shuffle/random state before action (and change back afterwards)
"${modifier}+Shift+bracketright" = "exec ${pkgs.playerctl}/bin/playerctl shuffle Toggle && ${pkgs.playerctl}/bin/playerctl next && ${pkgs.playerctl}/bin/playerctl shuffle Toggle";
"${modifier}+Shift+bracketleft" = "exec ${pkgs.playerctl}/bin/playerctl shuffle Toggle && ${pkgs.playerctl}/bin/playerctl previous && ${pkgs.playerctl}/bin/playerctl shuffle Toggle";
"Shift+XF86AudioNext" = "exec ${pkgs.playerctl}/bin/playerctl shuffle Toggle && ${pkgs.playerctl}/bin/playerctl next && ${pkgs.playerctl}/bin/playerctl shuffle Toggle";
# Previous/next
"${modifier}+bracketright" = "exec ${pkgs.playerctl}/bin/playerctl next";
"${modifier}+bracketleft" = "exec ${pkgs.playerctl}/bin/playerctl previous";
"XF86AudioNext" = "exec ${pkgs.playerctl}/bin/playerctl next";
"XF86AudioPrev" = "exec ${pkgs.playerctl}/bin/playerctl previous";
# Seek forward/back
"${modifier}+Ctrl+bracketright" = "exec ${pkgs.playerctl}/bin/playerctl position 5+";
"${modifier}+Ctrl+bracketleft" = "exec ${pkgs.playerctl}/bin/playerctl position 5-";
"Ctrl+XF86AudioNext" = "exec ${pkgs.playerctl}/bin/playerctl position 5+";
"Ctrl+XF86AudioPrev" = "exec ${pkgs.playerctl}/bin/playerctl position 5-";
# Toggle play/pause
"XF86AudioPlay" = "exec ${pkgs.playerctl}/bin/playerctl play-pause";
"XF86AudioPause" = "exec ${pkgs.playerctl}/bin/playerctl play-pause";
"${modifier}+backslash" = "exec ${pkgs.playerctl}/bin/playerctl play-pause";
"${modifier}+p" = "exec bash ${inputs.bwmenu}/bwmenu";
"${modifier}+e" = "exec bash ${inputs.bemoji}/bemoji -t";
"${modifier}+0" = "workspace 10";
"${modifier}+Shift+0" = "move container to workspace 10";
"Ctrl+Alt+l" = "exec ${pkgs.systemd}/bin/loginctl lock-session";
"${modifier}+s" = "sticky toggle";
}
// genKeyAttrs true
// genKeyAttrs false
);
menu = "${config.programs.rofi.package}/bin/rofi -show drun -show-icons -run-command '${pkgs.sway}/bin/swaymsg exec -- {cmd}'";
bars = [];
gaps = {
smartGaps = lib.mkDefault true;
smartBorders = lib.mkDefault "on";
inner = lib.mkDefault 10;
outer = lib.mkDefault 0;
};
};
};
programs.librewolf.enable = true;
programs.waybar = {
enable = lib.mkDefault true;
systemd = {
enable = lib.mkDefault true;
target = lib.mkDefault "sway-session.target";
};
settings.mainbar = {
position = lib.mkDefault "left";
height = lib.mkDefault null;
modules-left = ["sway/workspaces" "custom/spacer"];
modules-center = ["clock#1" "clock#2" "custom/spacer" "custom/media" "custom/spacer" "clock#3" "clock#4" "custom/spacer" "clock#5"];
modules-right = ["pulseaudio" "custom/spacer" "memory" "custom/spacer" "cpu"] ++ lib.optionals cfg.battery ["custom/spacer" "battery"] ++ ["custom/spacer" "tray"];
"custom/spacer" = {
format = lib.mkDefault "";
rotate = lib.mkDefault 90;
tooltip = lib.mkDefault false;
};
"custom/media" = {
rotate = lib.mkDefault 90;
max-length = lib.mkDefault 60;
on-click = lib.mkDefault "${pkgs.playerctl}/bin/playerctl play-pause";
exec = lib.mkDefault "${pkgs.playerctl}/bin/playerctl metadata --format '{{ emoji(status) }} {{ artist }} - {{ title }}' --follow";
};
"sway/workspaces" = {
disable-scroll = lib.mkDefault true;
};
"clock#1" = {
tooltip = lib.mkDefault false;
format = lib.mkDefault "{:%a}";
};
"clock#2" = {
tooltip = lib.mkDefault false;
format = lib.mkDefault "{:%m-%d}";
};
"clock#3" = {
tooltip = lib.mkDefault false;
format = lib.mkDefault "{:%I:%M}";
};
"clock#4" = {
tooltip = lib.mkDefault false;
format = lib.mkDefault "{:%p}";
};
"clock#5" = {
tooltip = lib.mkDefault false;
timezone = lib.mkDefault "Etc/UTC";
format = lib.mkDefault "{:%H%M}";
};
pulseaudio = {
format = lib.mkDefault "{icon} {volume}%";
format-bluetooth = lib.mkDefault "{icon} {volume}%";
format-muted = lib.mkDefault "";
format-icons = ["" "" ""];
on-click = lib.mkDefault "${pkgs.pulseaudio}/bin/pactl set-sink-mute @DEFAULT_SINK@ toggle";
on-click-right = lib.mkDefault "${pkgs.pavucontrol}/bin/pavucontrol";
ignored-sinks = ["Easy Effects Sink"];
};
memory = {
interval = lib.mkDefault 20;
format = lib.mkDefault " {}%";
};
cpu = {
interval = lib.mkDefault 20;
format = lib.mkDefault " {usage}%";
};
battery = {
states = {
good = lib.mkDefault 90;
warning = lib.mkDefault 25;
critical = lib.mkDefault 10;
};
format = lib.mkDefault "{icon} {capacity}%";
format-icons = {
default = ["" "" "" "" "" "" "" "" "" ""];
charging = ["" "" "" "" "" "" ""];
};
};
tray = {
icon-size = lib.mkDefault 18;
spacing = lib.mkDefault 5;
};
};
style = ''
window#waybar {
background: @base01;
color: @base06;
}
#custom-spacer {
font-size: 15px;
color: @base00;
font-weight: bold;
}
#workspaces,
#clock.1,
#clock.2,
#clock.3,
#clock.4,
#clock.5,
#pulseaudio,
#memory,
#cpu,
#battery,
#disk,
#tray,
#mode,
#custom-media {
color: @base06;
background: @base00;
padding: 5px 0;
}
#workspaces { padding: 0 }
#clock.1 { padding: 5px 0 0 0; }
#clock.2 { padding: 0 0 5px 0; }
#clock.3 { padding: 5px 0 0 0; }
#clock.4 { padding: 0 0 5px 0; }
#custom-media.playing {
color: @base0A;
}
#workspaces button.focused {
color: @base0A;
}
#workspaces button:hover {
background: @base02;
}
#pulseaudio {
color: @base0B;
}
#memory {
color: @base0C;
}
#cpu {
color: @base0D;
}
#battery {
color: @base0E;
}
* {
border-radius: 0;
border-width: 0;
border-style: none;
margin: 0;
padding: 0;
}
'';
};
services.mako = {
enable = lib.mkDefault true;
maxVisible = lib.mkDefault 6;
extraConfig = lib.generators.toKeyValue {} {
on-button-middle = "dismiss-all";
};
};
systemd.user.services.mako = {
Service = {
ExecStart = "${pkgs.mako}/bin/mako";
};
Install = {
After = ["sway-session.target"];
WantedBy = ["sway-session.target"];
};
};
stylix.enable = lib.mkDefault true;
services.blueman-applet.enable = lib.mkDefault cfg.bluetooth;
services.mpris-proxy.enable = lib.mkDefault true;
services.playerctld.enable = lib.mkDefault true;
gtk = {
enable = lib.mkDefault true;
iconTheme = {
package = lib.mkDefault pkgs.papirus-icon-theme;
name = lib.mkDefault "Papirus-Dark";
};
};
home.pointerCursor = {
package = lib.mkDefault pkgs.adwaita-icon-theme;
name = lib.mkDefault "Adwaita";
size = lib.mkDefault 24;
x11.enable = lib.mkDefault true;
gtk.enable = lib.mkDefault true;
};
qt = {
enable = lib.mkDefault true;
platformTheme = lib.mkDefault "gtk";
};
# programs.kermit = {
# enable = lib.mkDefault true;
# settings = {
# opacity = lib.mkDefault "0.90";
# key = lib.mkDefault "shift";
# };
# };
programs.foot.enable = true;
xdg.enable = true;
xdg.userDirs.enable = true;
xdg.configFile."mimeapps.list".force = true;
xdg.mimeApps = let
applications = {
"inode/directory" = "pcmanfm-qt.desktop";
"text/html" = "librewolf.desktop";
"x-scheme-handler/http" = "librewolf.desktop";
"x-scheme-handler/https" = "librewolf.desktop";
"x-scheme-handler/about" = "librewolf.desktop";
"application/zip" = "ark.desktop";
"application/rar" = "ark.desktop";
"application/7z" = "ark.desktop";
"application/*tar" = "ark.desktop";
};
in {
enable = true;
associations.added = applications;
defaultApplications = applications;
};
programs.mpv.enable = lib.mkDefault true;
fonts.fontconfig.enable = lib.mkDefault true;
home.packages = with pkgs; [
wl-clipboard
wtype
ydotool
keyutils
# programs
pavucontrol
kdePackages.ark
pcmanfm-qt
# CLI tools
yt-dlp
maim
slop
xorg.xhost
];
programs.rofi = {
enable = lib.mkDefault true;
terminal = lib.mkDefault "${pkgs.foot}/bin/foot";
};
services.flameshot = {
enable = true;
settings.General = {
filenamePattern = "%F_%T";
savePath = "${config.home.homeDirectory}/Media/Screenshots";
saveAfterCopy = true;
useGrimAdapter = true;
#uiColor = "#${lib.stylix.colors.base04}";
#contrastUiColor = "#${lib.stylix.colors.base05}";
};
};
services.clipman.enable = true;
};
}