# Dynamic Theme Switcher Module

A NixOS module that automatically generates and applies color themes from wallpapers using pywal16, with integrated wpaperd wallpaper management and support for GTK, Qt/Kvantum, Ghostty, and other applications.

## Features

- **Integrated Wallpaper Management**: Built-in wpaperd integration with configurable rotation modes
- **Automatic Color Extraction**: Uses pywal16 with configurable backends (haishoku, colorthief, etc.) to extract color palettes from wallpapers
- **Multi-Application Support**: Generates themes for GTK 3.0, GTK 4.0, Qt/Kvantum, Ghostty terminal, and more
- **Time-Based Switching**: Automatically switches between light and dark themes based on configured times
- **Flexible Rotation Modes**: Choose between continuous rotation, switch-only, or hybrid modes
- **Manual Control**: Provides scripts for manual theme switching
- **Synchronized Wallpaper & Theme**: Wallpaper and color theme always match

## Directory Structure

```
theme_switcher/
├── default.nix                    # Main module configuration
├── templates/
│   ├── gtk-3.0.css               # GTK 3.0 theme template
│   ├── gtk-4.0.css               # GTK 4.0 theme template
│   └── PywalTheme.kvconfig       # Kvantum Qt theme template
├── OUTLINE.md                     # Implementation specification
└── README.md                      # This file
```

## Installation

### 1. Import the Module

Add the module to your host configuration:

```nix
# In your host's configuration.nix or desktop-configuration.nix
imports = [
  ../../shared/modules/services/theme_switcher
];
```

### 2. Enable and Configure

```nix
services.themeSwitcher = {
  enable = true;
  user = "yourUsername";
  
  # Optional: Customize settings
  backend = "haishoku";  # Color extraction backend
  lightTime = "06:00:00";  # Switch to light theme at 6 AM
  darkTime = "18:00:00";   # Switch to dark theme at 6 PM
  enableAutoSwitch = true; # Enable automatic time-based switching
  
  # Wallpaper rotation settings
  rotation = {
    mode = "continuous";  # Options: continuous, switch-only, hybrid
    interval = "5m";      # Rotation interval (for continuous mode)
  };
  
  # Wpaperd configuration
  wpaperd = {
    enable = true;
    mode = "center";      # Options: center, fit, stretch, tile
    transition.effect = "fade";
    transition.duration = 300;  # milliseconds
  };
};
```

**Note:** If you were previously using the separate `wallpaper-rotator` module, you should disable it to avoid conflicts.

### 3. Wallpaper Directory Structure

Ensure your wallpaper directory has Light and Dark subdirectories:

```
wallpapers/
├── Light/
│   ├── wallpaper1.jpg
│   ├── wallpaper2.jpg
│   └── ...
└── Dark/
    ├── wallpaper1.jpg
    ├── wallpaper2.jpg
    └── ...
```

### 4. Rebuild Your System

```bash
sudo nixos-rebuild switch --flake .#hostname
```

## Configuration Options

### Core Options

#### `services.themeSwitcher.enable`
- **Type**: boolean
- **Default**: false
- **Description**: Enable the dynamic theme switcher with integrated wallpaper management

#### `services.themeSwitcher.user`
- **Type**: string
- **Required**: yes
- **Description**: Username for which to apply theme switching

#### `services.themeSwitcher.wallpaperPath`
- **Type**: string
- **Default**: `${homeDirectory}/nixos/shared/modules/services/wallpapers`
- **Description**: Path to wallpaper directories (must contain Light/ and Dark/ subdirectories)

#### `services.themeSwitcher.backend`
- **Type**: enum
- **Default**: `"haishoku"`
- **Options**: `"haishoku"`, `"modern_colorthief"`, `"fast_colorthief"`, `"colorthief"`, `"colorz"`, `"wal"`
- **Description**: Pywal color extraction backend algorithm

#### `services.themeSwitcher.lightTime`
- **Type**: string
- **Default**: `"06:00:00"`
- **Description**: Time to switch to light theme (HH:MM:SS format)

#### `services.themeSwitcher.darkTime`
- **Type**: string
- **Default**: `"18:00:00"`
- **Description**: Time to switch to dark theme (HH:MM:SS format)

#### `services.themeSwitcher.enableAutoSwitch`
- **Type**: boolean
- **Default**: true
- **Description**: Enable automatic time-based theme switching via systemd timer

### Rotation Options

#### `services.themeSwitcher.rotation.mode`
- **Type**: enum
- **Default**: `"continuous"`
- **Options**: 
  - `"continuous"`: Rotate wallpapers every interval AND regenerate theme each time
  - `"switch-only"`: Only change wallpaper at light/dark switch times (6 AM/6 PM)
  - `"hybrid"`: Rotate wallpapers but only regenerate theme at switch times (not yet implemented)
- **Description**: Wallpaper rotation and theme generation behavior

#### `services.themeSwitcher.rotation.interval`
- **Type**: string
- **Default**: `"5m"`
- **Example**: `"30s"`, `"10m"`, `"1h"`
- **Description**: How often to rotate wallpapers in continuous mode

#### `services.themeSwitcher.rotation.sorting`
- **Type**: enum
- **Default**: `"random"`
- **Options**: `"random"`
- **Description**: Wallpaper selection method (currently only random is supported)

### Wpaperd Integration Options

#### `services.themeSwitcher.wpaperd.enable`
- **Type**: boolean
- **Default**: true
- **Description**: Enable wpaperd wallpaper daemon integration

#### `services.themeSwitcher.wpaperd.mode`
- **Type**: enum
- **Default**: `"center"`
- **Options**: `"center"`, `"fit"`, `"fit-border-color"`, `"stretch"`, `"tile"`
- **Description**: How to display wallpapers when size differs from display resolution

#### `services.themeSwitcher.wpaperd.transition.effect`
- **Type**: string
- **Default**: `"fade"`
- **Example**: `"simple"`, `"fade"`
- **Description**: Wallpaper transition effect name

#### `services.themeSwitcher.wpaperd.transition.duration`
- **Type**: integer
- **Default**: 300
- **Description**: Transition duration in milliseconds

## Manual Usage

### Apply Theme Manually

The module installs `apply-theme.sh` to `~/.local/bin/`:

```bash
# Apply light theme with random wallpaper from Light/ directory
~/.local/bin/apply-theme.sh --light

# Apply dark theme with random wallpaper from Dark/ directory
~/.local/bin/apply-theme.sh --dark

# Apply theme with specific wallpaper
~/.local/bin/apply-theme.sh --light --wallpaper-path /path/to/wallpaper.jpg
```

### Check Systemd Timer Status

```bash
# View timer status
systemctl --user status theme-switcher.timer

# List upcoming timer events
systemctl --user list-timers | grep theme

# Manually trigger theme switch
systemctl --user start theme-switcher.service

# View service logs
journalctl --user -u theme-switcher.service
```

### Test Pywal Color Extraction

```bash
# Test light theme generation
wal -i ~/nixos/shared/modules/services/wallpapers/Light/IU-Light.jpg --backend haishoku -l -n

# Test dark theme generation
wal -i ~/nixos/shared/modules/services/wallpapers/Dark/IU-Dark.jpg --backend haishoku -n

# View generated colors
cat ~/.cache/wal/colors.json

# View generated templates
ls -la ~/.cache/wal/
```

## Generated Files

After running the theme switcher, pywal generates the following files:

### Pywal Cache (`~/.cache/wal/`)
- `colors.json` - Extracted color palette in JSON format
- `colors.sh` - Shell script with color variables
- `ghostty.conf` - Ghostty terminal theme (auto-reloads)
- `gtk-3.0.css` - GTK 3.0 theme (from custom template)
- `gtk-4.0.css` - GTK 4.0 theme (from custom template)
- `PywalTheme.kvconfig` - Kvantum Qt theme (from custom template)

### User Configuration
- `~/.config/gtk-3.0/gtk.css` - Symlink to pywal-generated GTK3 theme
- `~/.config/gtk-4.0/gtk.css` - Symlink to pywal-generated GTK4 theme
- `~/.config/Kvantum/PywalTheme/PywalTheme.kvconfig` - Kvantum theme copy

## Integration with Existing Themes

When enabling this module, you should adjust your existing theme configuration:

### Before (Static Catppuccin Theme)
```nix
gtk = {
  enable = true;
  theme = {
    name = "catppuccin-macchiato-lavender-compact+rimless";
    package = pkgs.catppuccin-gtk.override { ... };
  };
};

qt = {
  enable = true;
  platformTheme.name = "kvantum";
  style.name = "kvantum";
};

xdg.configFile."Kvantum/kvantum.kvconfig".source = ...;
```

### After (Dynamic Pywal Theme)
```nix
# The theme switcher module automatically sets:
# - gtk.enable = true
# - qt.enable = true
# - qt.platformTheme.name = "kvantum"
# - qt.style.name = "kvantum"

# You can still keep static icon and cursor themes:
gtk.iconTheme = {
  name = "Papirus-Dark";
  package = pkgs.catppuccin-papirus-folders;
};

gtk.cursorTheme = {
  name = "Bibata-Modern-Classic";
  package = pkgs.bibata-cursors;
};
```

## Troubleshooting

### Theme Not Applying
```bash
# Check if pywal generated files
ls -la ~/.cache/wal/

# Check systemd service status
systemctl --user status theme-switcher.service

# View detailed logs
journalctl --user -u theme-switcher.service -n 50

# Manually run apply-theme.sh with verbose output
~/.local/bin/apply-theme.sh --light
```

### Kvantum Theme Not Working
```bash
# Check if Kvantum theme was created
ls -la ~/.config/Kvantum/PywalTheme/

# Manually set Kvantum theme
kvantummanager --set PywalTheme

# Check if Qt applications are using Kvantum
echo $QT_STYLE_OVERRIDE  # Should be "kvantum"
```

### Colors Don't Match Wallpaper
Try a different pywal backend:
```nix
services.themeSwitcher.backend = "modern_colorthief";  # or "fast_colorthief", "colorthief", etc.
```

### GTK Applications Not Updating
```bash
# Check if GTK CSS files exist
ls -la ~/.config/gtk-3.0/gtk.css
ls -la ~/.config/gtk-4.0/gtk.css

# Restart GTK applications for changes to take effect
```

## Supported Applications

### Automatically Themed
- **GTK 3 Applications**: Nautilus, GNOME Calculator, etc.
- **GTK 4 Applications**: GNOME Text Editor, newer GNOME apps
- **Qt Applications**: KDE apps when using Kvantum
- **Ghostty Terminal**: Auto-reloads on config change
- **Waybar**: If using pywal template (built-in)
- **Rofi**: If using pywal template (built-in)
- **Hyprland/Sway**: If using pywal template (built-in)

### Manual Integration Required
- **Firefox**: Use pywal-firefox extension
- **VSCode**: Use pywal theme extension
- **Other Applications**: Check if pywal templates exist in `~/.cache/wal/`

## Advanced Usage

### Custom Pywal Templates

To add your own templates, create files in `~/.config/wal/templates/`:

```bash
# Template file: ~/.config/wal/templates/myapp.conf
# Use pywal template variables
background = {background}
foreground = {foreground}
color0 = {color0}
...
color15 = {color15}
```

After running `apply-theme.sh`, find your generated file in `~/.cache/wal/myapp.conf`.

### Disable Automatic Switching

To use manual control only:
```nix
services.themeSwitcher = {
  enable = true;
  user = "username";
  enableAutoSwitch = false;  # Disable timer
};
```

Then use `~/.local/bin/apply-theme.sh` manually as needed.

### Rotation Modes Explained

#### Continuous Mode (Default)
- Wallpaper rotates every interval (e.g., 5 minutes)
- Theme is regenerated from each new wallpaper
- Wallpaper and theme always match
- **Resource usage**: Moderate (pywal runs every interval)
- **Best for**: Users who want frequently changing, perfectly matched themes

#### Switch-Only Mode
- Wallpaper changes only at light/dark switch times (6 AM / 6 PM)
- Theme is generated once per switch
- Wallpaper and theme always match
- **Resource usage**: Minimal (pywal runs twice per day)
- **Best for**: Users who prefer consistent themes throughout the day

#### Hybrid Mode (Future)
- Wallpaper rotates every interval
- Theme is generated only at switch times
- Wallpaper and theme may not match mid-day
- **Not yet implemented**

### Migration from wallpaper-rotator Module

If you were previously using the separate `wallpaper-rotator` module:

1. **Disable the old module** in your configuration:
   ```nix
   # Comment out or remove:
   # services.wallpaperRotator.enable = true;
   ```

2. **Enable themeSwitcher** with equivalent settings:
   ```nix
   services.themeSwitcher = {
     enable = true;
     user = "yourUsername";
     rotation.interval = "5m";  # Same as old duration setting
     wpaperd.mode = "center";   # Same as old mode setting
   };
   ```

3. **Rebuild** your system - wpaperd will now be managed by themeSwitcher

## Technical Details

- **Pywal Template Syntax**: `{background}`, `{foreground}`, `{color0}`-`{color15}`, `{cursor}`, `{wallpaper}`
- **Template Location**: `~/.config/wal/templates/filename.ext`
- **Output Location**: `~/.cache/wal/filename.ext`
- **Color Extraction**: 16-color palette using pywal16
- **GTK Reload**: Automatic via gsettings changes
- **Kvantum Reload**: May require app restart
- **Ghostty Reload**: Automatic on config file change

## Future Enhancements

- Direct wpaperd integration (trigger theme change on wallpaper rotation)
- Per-monitor theme configuration
- Additional application templates (Firefox, VSCode, etc.)
- Theme preview before applying
- Fallback color schemes for monochrome wallpapers

## Credits

- Built for NixOS using home-manager
- Uses [pywal16](https://github.com/eylles/pywal16) for color extraction
- Based on [pywal](https://github.com/dylanaraps/pywal) original concept
