Skip to content

Commit

Permalink
Implementing sorting
Browse files Browse the repository at this point in the history
  • Loading branch information
anufrievroman committed Aug 27, 2023
1 parent bd53bcf commit b5b383c
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 12 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,10 @@ To restore your wallpaper at launch, add `waypaper --restore` to your startup co
## Roadmap

- ~Improve loading of folders with many images~.
- Additional options for ~search in subfolders~, ~background color~, and setting a uniform color.
- Additional options for ~search in subfolders~, ~background color~, ~sorting~, and setting a uniform color.
- Support for other backends like ~swww~, ~feh~, ~wallutils~, wbg, and hyprpaper.
- Better keyboard-driven experience and hjkl support.
- Support for multiple monitors

## Contributions

Expand Down
2 changes: 1 addition & 1 deletion waypaper/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from waypaper.arguments import args


__version__ = "1.6"
__version__ = "1.7"


def run():
Expand Down
86 changes: 76 additions & 10 deletions waypaper/app.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
"""Module that runs GUI app"""
from waypaper.changer import change_wallpaper
from waypaper.config import cf
from waypaper.options import FILL_OPTIONS, BACKEND_OPTIONS

import threading
import os
import shutil
import distutils.spawn
import gi

from waypaper.changer import change_wallpaper
from waypaper.config import cf
from waypaper.options import FILL_OPTIONS, BACKEND_OPTIONS, SORT_OPTIONS, SORT_DISPLAYS

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GdkPixbuf, Gdk, GLib


def has_image_extension(file_path):
"""Check if the file has image extension"""
image_extensions = ['.gif', '.jpg', '.jpeg', '.png']
ext = os.path.splitext(file_path)[1].lower()
return ext in image_extensions


def get_image_paths(root_folder, include_subfolders=False, depth=None):
"""Get a list of file paths depending of weather we include subfolders and how deep we scan"""
image_paths = []
Expand All @@ -23,7 +32,7 @@ def get_image_paths(root_folder, include_subfolders=False, depth=None):
if current_depth > depth:
continue
for filename in files:
if filename.endswith(".jpg") or filename.endswith(".png") or filename.endswith(".gif"):
if has_image_extension(filename):
image_paths.append(os.path.join(root, filename))
return image_paths

Expand Down Expand Up @@ -93,8 +102,8 @@ def init_ui(self):

# Set as active line the backend from config, if it is installed:
try:
filtered_backends = [value for value, miss in zip(BACKEND_OPTIONS, self.missing_backends) if not miss]
active_num = filtered_backends.index(cf.backend)
installed_backends = [value for value, miss in zip(BACKEND_OPTIONS, self.missing_backends) if not miss]
active_num = installed_backends.index(cf.backend)
except:
active_num = 0
self.backend_option_combo.set_active(active_num)
Expand All @@ -116,10 +125,22 @@ def init_ui(self):
self.color_picker_button.set_rgba(rgba_color)
self.color_picker_button.connect("color-set", self.on_color_set)

# Create a sort option dropdown menu:
self.sort_option_combo = Gtk.ComboBoxText()
for option in SORT_OPTIONS:
self.sort_option_combo.append_text(SORT_DISPLAYS[option])
active_num = SORT_OPTIONS.index(cf.sort_option)
self.sort_option_combo.set_active(active_num)
self.sort_option_combo.connect("changed", self.on_sort_option_changed)

# Create exit button:
self.exit_button = Gtk.Button(label=" Exit ")
self.exit_button.connect("clicked", self.on_exit_clicked)

# Create refresh button:
self.refresh_button = Gtk.Button(label=" Refresh ")
self.refresh_button.connect("clicked", self.on_refresh_clicked)

# Create a box to contain the bottom row of buttons with margin:
self.bottom_button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=20)
self.bottom_button_box.set_margin_bottom(10)
Expand All @@ -137,7 +158,9 @@ def init_ui(self):
# Create a horizontal box for display option and exit button:
self.options_box = Gtk.HBox(spacing=10)
self.options_box.pack_end(self.exit_button, False, False, 0)
self.options_box.pack_end(self.refresh_button, False, False, 0)
self.options_box.pack_end(self.include_subfolders_checkbox, False, False, 0)
self.options_box.pack_end(self.sort_option_combo, False, False, 0)
self.options_box.pack_end(self.color_picker_button, False, False, 0)
self.options_box.pack_end(self.fill_option_combo, False, False, 0)
self.options_box.pack_end(self.backend_option_combo, False, False, 0)
Expand Down Expand Up @@ -179,10 +202,23 @@ def show_no_backend_message(self, message):
dialog.destroy()


def sort_images(self):
"""Sort images depending on the sorting option"""
if cf.sort_option == "name":
self.image_paths.sort(key=lambda x: os.path.basename(x))
elif cf.sort_option == "namerev":
self.image_paths.sort(key=lambda x: os.path.basename(x), reverse=True)
elif cf.sort_option == "date":
self.image_paths.sort(key=lambda x: os.path.getmtime(x))
elif cf.sort_option == "daterev":
self.image_paths.sort(key=lambda x: os.path.getmtime(x), reverse=True)


def process_images(self):
"""Load images from the selected folder, resize them, and arrange into a grid"""

self.image_paths = get_image_paths(cf.image_folder, cf.include_subfolders, depth=1)
self.sort_images()

# Show caching label:
self.loading_label = Gtk.Label(label=f"Caching {len(self.image_paths)} wallpapers...")
Expand Down Expand Up @@ -266,6 +302,14 @@ def on_fill_option_changed(self, combo):
cf.fill_option = combo.get_active_text()


def on_sort_option_changed(self, combo):
"""Save sort parameter whet it is changed"""
selected_option = combo.get_active_text()
selected_option_num = list(SORT_DISPLAYS.values()).index(selected_option)
cf.sort_option = list(SORT_DISPLAYS.keys())[selected_option_num]
threading.Thread(target=self.process_images).start()


def on_backend_option_changed(self, combo):
"""Save backend parameter whet it is changed"""
cf.backend = combo.get_active_text()
Expand All @@ -289,17 +333,39 @@ def on_image_clicked(self, widget, user_data):
cf.save()


def on_refresh_clicked(self, widget):
"""On clicking refresh button, clear cache"""
self.clear_cache()


def on_exit_clicked(self, widget):
"""On clicking exit button, save the data and quit"""
"""On clicking exit button, exit"""
self.exit_app()


def exit_app(self):
"""Save the data and quit"""
cf.save()
Gtk.main_quit()


def clear_cache(self):
"""Delete cache folder and reprocess the images"""
cache_folder = f"{cf.config_folder}/.cache"
try:
shutil.rmtree(cache_folder)
os.makedirs(cache_folder)
except OSError as e:
print(f"Error deleting cache '{cache_folder}': {e}")
threading.Thread(target=self.process_images).start()


def on_key_pressed(self, widget, event):
"""On clicking q, save the data and quit"""
"""Process various key bindigns"""
if event.keyval == Gdk.KEY_q:
cf.save()
Gtk.main_quit()
self.exit_app()
if event.keyval == Gdk.KEY_r:
self.clear_cache()


def run(self):
Expand Down
9 changes: 9 additions & 0 deletions waypaper/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import os

from waypaper.arguments import args
from waypaper.options import FILL_OPTIONS, SORT_OPTIONS


class Config:
Expand All @@ -15,6 +16,7 @@ def __init__(self):
self.image_folder = str(pathlib.Path.home()) + "/Pictures"
self.wallpaper = None
self.fill_option = "fill"
self.sort_option = "name"
self.backend = "swaybg"
self.color = "#ffffff"
self.include_subfolders = False
Expand All @@ -28,6 +30,7 @@ def create(self):
config["Settings"] = {
"folder": str(self.image_folder),
"fill": str(self.fill_option),
"sort": str(self.sort_option),
"backend": str(self.backend),
"color": str(self.color),
"subfolders": str(self.include_subfolders),
Expand All @@ -45,6 +48,11 @@ def read(self):
self.image_folder = config.get("Settings", "folder", fallback=self.image_folder)
self.wallpaper = config.get("Settings", "wallpaper", fallback=self.wallpaper)
self.fill_option = config.get("Settings", "fill", fallback=self.fill_option)
if self.fill_option not in FILL_OPTIONS:
self.sort_option = FILL_OPTIONS[0]
self.sort_option = config.get("Settings", "sort", fallback=self.sort_option)
if self.sort_option not in SORT_OPTIONS:
self.sort_option = SORT_OPTIONS[0]
self.backend = config.get("Settings", "backend", fallback=self.backend)
self.color = config.get("Settings", "color", fallback=self.color)
self.include_subfolders = config.getboolean("Settings", "subfolders", fallback=self.include_subfolders)
Expand All @@ -60,6 +68,7 @@ def save(self):
config.set("Settings", "folder", cf.image_folder)
config.set("Settings", "wallpaper", cf.wallpaper)
config.set("Settings", "fill", cf.fill_option)
config.set("Settings", "sort", cf.sort_option)
config.set("Settings", "backend", cf.backend)
config.set("Settings", "color", cf.color)
config.set("Settings", "subfolders", str(cf.include_subfolders))
Expand Down
6 changes: 6 additions & 0 deletions waypaper/options.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
BACKEND_OPTIONS = ["swaybg", "swww", "feh", "wallutils"]
FILL_OPTIONS = ["fill", "stretch", "fit", "center", "tile"]
SORT_OPTIONS = ["name", "namerev", "date", "daterev"]
SORT_DISPLAYS = {
"name": "Sort by name ↓",
"namerev": "Sort by name ↑",
"date": "Sort by date ↓",
"daterev": "Sort by date ↑"}

0 comments on commit b5b383c

Please sign in to comment.