Merge pull request #71 from PhilippHeuer/feat/override-folder-and-state

feat: add folder cli arg, move app state into separate file
This commit is contained in:
Roman 2024-09-01 13:32:43 +09:00 committed by GitHub
commit 75a8832f05
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 107 additions and 19 deletions

View File

@ -47,6 +47,8 @@ parser.add_argument("--restore", help=txt.msg_arg_rest, action="store_true")
parser.add_argument("--random", help=txt.msg_arg_rand, action="store_true")
parser.add_argument("--fill", help=txt.msg_arg_fill, choices=FILL_OPTIONS)
parser.add_argument("--wallpaper", help=txt.msg_arg_wall)
parser.add_argument("--folder", help=txt.msg_arg_folder)
parser.add_argument("--state-file", help=txt.msg_arg_statefile)
parser.add_argument("--backend", help=txt.msg_arg_back, choices=BACKEND_OPTIONS)
parser.add_argument("--list", help=txt.msg_arg_list, action='store_true')
args = parser.parse_args()
@ -54,8 +56,13 @@ args = parser.parse_args()
def run():
"""Read user arguments and either run GUI app or just reset the wallpaper"""
cf.read()
cf.read_state() # read default state file, if use_xdg_state is True
cf.read_parameters_from_user_arguments(args)
if args.state_file:
cf.read_state() # read from custom state file if provided
cf.read_parameters_from_user_arguments(args) # ensure that user arguments override values from state file
cf.check_validity()
# Set the wallpaper and quit:
if args.restore or args.random:
@ -99,7 +106,7 @@ def run():
sys.exit(0)
# Start GUI:
app = App(txt)
app = App(txt, cf)
app.run()

View File

@ -52,9 +52,9 @@ def cache_image(image_path: str, cache_dir: Path) -> None:
class App(Gtk.Window):
"""Main application class that controls GUI"""
def __init__(self, txt: Chinese|English|French|German|Polish|Russian|Belarusian|Spanish) -> None:
def __init__(self, txt: Chinese|English|French|German|Polish|Russian|Belarusian|Spanish, cf: Config) -> None:
super().__init__(title="Waypaper")
self.cf = Config()
self.cf = cf
self.about = AboutData()
self.txt = txt
self.check_backends()
@ -112,7 +112,11 @@ class App(Gtk.Window):
for option in FILL_OPTIONS:
capitalized_option = option[0].upper() + option[1:]
self.fill_option_combo.append_text(capitalized_option)
self.fill_option_combo.set_active(0)
if self.cf.fill_option in FILL_OPTIONS:
active_fill_option_index = FILL_OPTIONS.index(self.cf.fill_option)
self.fill_option_combo.set_active(active_fill_option_index)
else:
self.fill_option_combo.set_active(0)
self.fill_option_combo.connect("changed", self.on_fill_option_changed)
self.fill_option_combo.set_tooltip_text(self.txt.tip_fill)

View File

@ -3,8 +3,10 @@
import configparser
from argparse import Namespace
import pathlib
import os
from sys import exit
from platformdirs import user_config_path, user_pictures_path, user_cache_path, user_state_path
from typing import List
from platformdirs import user_config_path, user_pictures_path, user_cache_path
from waypaper.aboutdata import AboutData
from waypaper.options import FILL_OPTIONS, SORT_OPTIONS, SWWW_TRANSITION_TYPES, BACKEND_OPTIONS
@ -41,13 +43,15 @@ class Config:
self.cache_dir = user_cache_path(self.about.applicationName())
self.config_dir = user_config_path(self.about.applicationName())
self.config_file = self.config_dir / "config.ini"
self.state_dir = user_state_path(self.about.applicationName())
self.state_file = self.state_dir / "state.ini"
self.use_xdg_state = False
# Create config and cache folders:
self.config_dir.mkdir(parents=True, exist_ok=True)
self.cache_dir.mkdir(parents=True,exist_ok=True)
self.state_dir.mkdir(parents=True, exist_ok=True)
self.read()
self.check_validity()
def select_wallpaper(self, path_str: str) -> None:
self.selected_wallpaper = pathlib.Path(path_str)
@ -70,9 +74,7 @@ class Config:
config = configparser.ConfigParser()
config.read(self.config_file, 'utf-8')
# Read parameters:
image_folder_str = config.get("Settings", "folder", fallback=self.image_folder)
self.image_folder = pathlib.Path(image_folder_str).expanduser()
# Read basic parameters:
self.fill_option = config.get("Settings", "fill", fallback=self.fill_option)
self.sort_option = config.get("Settings", "sort", fallback=self.sort_option)
self.backend = config.get("Settings", "backend", fallback=self.backend)
@ -87,22 +89,44 @@ class Config:
self.include_subfolders = config.getboolean("Settings", "subfolders", fallback=self.include_subfolders)
self.show_hidden = config.getboolean("Settings", "show_hidden", fallback=self.show_hidden)
self.show_gifs_only = config.getboolean("Settings", "show_gifs_only", fallback=self.show_gifs_only)
self.use_xdg_state = config.getboolean("Settings", "use_xdg_state", fallback=self.use_xdg_state)
# Read and convert strings representing lists and paths:
image_folder_str = config.get("Settings", "folder", fallback=self.image_folder)
monitors_str = config.get("Settings", "monitors", fallback=self.selected_monitor, raw=True)
wallpapers_str = config.get("Settings", "wallpaper", fallback="", raw=True)
self.image_folder = pathlib.Path(image_folder_str).expanduser()
if monitors_str:
self.monitors = [str(monitor) for monitor in monitors_str.split(",")]
if wallpapers_str:
self.wallpapers = [pathlib.Path(paper).expanduser() for paper in wallpapers_str.split(",")]
# Check the validity of the number of columns:
# Read and check the validity of the number of columns:
try:
self.number_of_columns = config.getint("Settings", "number_of_columns", fallback=self.number_of_columns)
self.number_of_columns = int(self.number_of_columns) if int(self.number_of_columns) > 0 else 3
except Exception:
self.number_of_columns = 3
# Convert strings to lists:
def read_state(self) -> None:
"""Load data from the state.ini file"""
if not self.use_xdg_state:
return
state = configparser.ConfigParser()
state.read(self.state_file, 'utf-8')
# Read and convert strings representing lists and paths:
image_folder_str = state.get("State", "folder", fallback=self.image_folder)
monitors_str = state.get("State", "monitors", fallback=self.selected_monitor, raw=True)
wallpapers_str = state.get("State", "wallpaper", fallback="", raw=True)
self.image_folder = pathlib.Path(image_folder_str).expanduser()
if monitors_str:
self.monitors = [str(monitor) for monitor in monitors_str.split(",")]
if wallpapers_str:
self.wallpapers = [pathlib.Path(paper).expanduser() for paper in wallpapers_str.split(",")]
def check_validity(self) -> None:
"""Check if the config parameters are valid and correct them if needed"""
if self.backend not in BACKEND_OPTIONS:
@ -114,11 +138,17 @@ class Config:
if self.swww_transition_type not in SWWW_TRANSITION_TYPES:
self.swww_transition_type = "any"
# Check the validity of the number of columns:
try:
self.number_of_columns = int(self.number_of_columns) if int(self.number_of_columns) > 0 else 3
except Exception:
self.number_of_columns = 3
if 0 > int(self.swww_transition_angle) > 180:
self.swww_transition_angle = 0
if 0 > int(self.swww_transition_step) > 255:
self.swww_transition_step = 90
if 0 > int(self.swww_transition_duration):
if 0 > float(self.swww_transition_duration):
self.swww_transition_duration = 2
if 0 > int(self.swww_transition_fps):
self.swww_transition_fps = 60
@ -148,10 +178,13 @@ class Config:
if not config.has_section("Settings"):
config.add_section("Settings")
config.set("Settings", "language", self.lang)
config.set("Settings", "folder", self.shorten_path(self.image_folder))
config.set("Settings", "wallpaper", self.shortened_paths(self.wallpapers))
if not self.use_xdg_state:
config.set("Settings", "folder", self.shorten_path(self.image_folder))
config.set("Settings", "monitors", ",".join(self.monitors))
config.set("Settings", "wallpaper", self.shortened_paths(self.wallpapers))
config.set("Settings", "backend", self.backend)
config.set("Settings", "monitors", ",".join(self.monitors))
config.set("Settings", "fill", self.fill_option)
config.set("Settings", "sort", self.sort_option)
config.set("Settings", "color", self.color)
@ -165,9 +198,32 @@ class Config:
config.set("Settings", "swww_transition_angle", str(self.swww_transition_angle))
config.set("Settings", "swww_transition_duration", str(self.swww_transition_duration))
config.set("Settings", "swww_transition_fps", str(self.swww_transition_fps))
config.set("Settings", "use_xdg_state", str(self.use_xdg_state))
with open(self.config_file, "w") as configfile:
config.write(configfile)
# Save state file:
self.save_state()
def save_state(self) -> None:
"""Save the current state of the application"""
if not self.use_xdg_state:
return
self.attribute_selected_wallpaper()
# Write state to the file:
state = configparser.ConfigParser()
state.read(self.state_file)
if not state.has_section("State"):
state.add_section("State")
state.set("State", "folder", self.shorten_path(self.image_folder))
state.set("State", "monitors", ",".join(self.monitors))
state.set("State", "wallpaper", self.shortened_paths(self.wallpapers))
with open(self.state_file, "w") as statefile:
state.write(statefile)
def read_parameters_from_user_arguments(self, args: Namespace) -> None:
"""
Read user arguments provided at the run. These values take priority over config.ini
@ -177,4 +233,9 @@ class Config:
self.backend = args.backend
if args.fill:
self.fill_option = args.fill
if args.folder:
self.image_folder = pathlib.Path(args.folder).expanduser()
if args.state_file:
self.use_xdg_state = True # Use of a custom state file implies state is in a separate file, requires use_xdg_state
self.state_file = pathlib.Path(args.state_file).expanduser()

View File

@ -13,6 +13,8 @@ class English:
self.msg_arg_rand = "set a random wallpaper"
self.msg_arg_list = "list wallpapers in json to standard out"
self.msg_arg_wall = "set the specified wallpaper"
self.msg_arg_folder = "specify which folder to scan for wallpapers"
self.msg_arg_statefile = "specify a custom file to store the application state"
self.msg_path = "Selected image path:"
self.msg_select = "Select"
@ -63,7 +65,9 @@ class German:
self.msg_arg_back = "legt das Backend fest, welches zum Setzen des Hintergrundbildes verwendet werden soll"
self.msg_arg_rand = "wählt ein zufälliges Hintergrundbild aus"
self.msg_arg_list = "list wallpapers in json to standard out"
self.msg_arg_wall = "set the specified wallpaper"
self.msg_arg_wall = "setzt das angegebene Hintergrundbild"
self.msg_arg_folder = "legt fest, welcher Ordner nach Hintergrundbildern durchsucht werden soll"
self.msg_arg_statefile = "specify a custom file to store the application state"
self.msg_path = "Pfad zum ausgewählten Bild:"
self.msg_select = "Auswählen"
@ -115,6 +119,8 @@ class French:
self.msg_arg_rand = "définir un papier peint aléatoire"
self.msg_arg_list = "list wallpapers in json to standard out"
self.msg_arg_wall = "set the specified wallpaper"
self.msg_arg_folder = "specify which folder to scan for wallpapers"
self.msg_arg_statefile = "specify a custom file to store the application state"
self.msg_path = "Chemin de l'image sélectionnée :"
self.msg_select = "Sélectionner"
@ -166,6 +172,8 @@ class Polish:
self.msg_arg_rand = "ustaw losową tapetę"
self.msg_arg_list = "list wallpapers in json to standard out"
self.msg_arg_wall = "set the specified wallpaper"
self.msg_arg_folder = "specify which folder to scan for wallpapers"
self.msg_arg_statefile = "specify a custom file to store the application state"
self.msg_path = "Wybrana ścieżka obrazu:"
self.msg_select = "Wybierz"
@ -217,6 +225,8 @@ class Russian:
self.msg_arg_rand = "установить случайные обои"
self.msg_arg_list = "вывести обои и мотиноры в формате json"
self.msg_arg_wall = "указать путь к изображению"
self.msg_arg_folder = "specify which folder to scan for wallpapers"
self.msg_arg_statefile = "specify a custom file to store the application state"
self.msg_path = "Выбранный путь к изображению:"
self.msg_select = "Выбрать"
@ -268,6 +278,8 @@ class Belarusian:
self.msg_arg_rand = "ўсталяваць выпадковыя шпалеры"
self.msg_arg_list = "вывесці шпалеры і матыноры ў фармаце json"
self.msg_arg_wall = "пазначыць шлях да выявы"
self.msg_arg_folder = "specify which folder to scan for wallpapers"
self.msg_arg_statefile = "specify a custom file to store the application state"
self.msg_path = "Абраны шлях да выявы:"
self.msg_select = "Выбраць"
@ -319,6 +331,8 @@ class Chinese:
self.msg_arg_rand = "设置随机壁纸"
self.msg_arg_list = "list wallpapers in json to standard out"
self.msg_arg_wall = "set the specified wallpaper"
self.msg_arg_folder = "specify which folder to scan for wallpapers"
self.msg_arg_statefile = "specify a custom file to store the application state"
self.msg_path = "选择的图像路径:"
self.msg_select = "选择"
@ -369,6 +383,8 @@ class Spanish:
self.msg_arg_rand = "aplica una imagen de fondo aleatoria"
self.msg_arg_list = 'imprime un listado de las imágenes de fondo al terminal en formato "JSON"'
self.msg_arg_wall = "establece el fondo especificado"
self.msg_arg_folder = "specify which folder to scan for wallpapers"
self.msg_arg_statefile = "specify a custom file to store the application state"
self.msg_path = "Ubicación de la imagen:"
self.msg_select = "Selecciona"