Files
2026-07-31 12:51:28 +08:00

177 lines
6.0 KiB
Python

import os
import threading
import logging
from PIL import Image
import pystray
import config
import fetcher
import wallpaper
logger = logging.getLogger(__name__)
STYLES = ["fill", "fit", "stretch", "tile", "center"]
STYLE_LABELS = {"fill": "填充", "fit": "适应", "stretch": "拉伸", "tile": "平铺", "center": "居中"}
def _get_icon_path():
return os.path.join(config._get_app_dir(), "assets", "icon.ico")
class TrayApp:
def __init__(self):
self._icon = None
self._auto_timer = None
self._running = False
def run(self):
self._running = True
image = Image.open(_get_icon_path())
self._icon = pystray.Icon(
"WallpaperChanger",
image,
"壁纸更换器",
menu=self._build_menu(),
)
self._icon.title = "壁纸更换器"
if config.get("auto_refresh.enabled"):
self._start_auto_refresh()
self._icon.run()
def stop(self):
self._running = False
self._stop_auto_refresh()
if self._icon:
self._icon.stop()
def _build_menu(self):
show_notify = config.get("wallpaper.show_notification", True)
notify_label = "弹出通知: 开" if show_notify else "弹出通知: 关"
return pystray.Menu(
pystray.MenuItem("刷新壁纸", self._on_refresh, default=True),
pystray.MenuItem("自动刷新", self._auto_refresh_submenu()),
pystray.MenuItem("填充方式", self._fill_style_submenu()),
pystray.Menu.SEPARATOR,
pystray.MenuItem(notify_label, self._on_toggle_notification),
pystray.Menu.SEPARATOR,
pystray.MenuItem("安装右键菜单", self._on_install_menu),
pystray.MenuItem("卸载右键菜单", self._on_uninstall_menu),
pystray.Menu.SEPARATOR,
pystray.MenuItem("退出", self._on_exit),
)
def _auto_refresh_submenu(self):
enabled = config.get("auto_refresh.enabled", False)
label = "状态: 开启" if enabled else "状态: 关闭"
return pystray.Menu(
pystray.MenuItem(label, None),
pystray.Menu.SEPARATOR,
pystray.MenuItem("开启", self._on_auto_on),
pystray.MenuItem("关闭", self._on_auto_off),
)
def _fill_style_submenu(self):
items = []
for s in STYLES:
items.append(
pystray.MenuItem(
STYLE_LABELS[s],
self._on_set_fill_style,
checked=lambda item, _s=s: _s == config.get("wallpaper.fill_style", "fill"),
)
)
return pystray.Menu(*items)
def _on_refresh(self, icon, item=None):
threading.Thread(target=self._do_refresh, daemon=True).start()
def _do_refresh(self):
try:
image_path = fetcher.fetch_wallpaper()
fill_style = config.get("wallpaper.fill_style", "fill")
ok = wallpaper.set_wallpaper(image_path, fill_style)
if ok and self._icon:
if config.get("wallpaper.show_notification", True):
self._icon.notify("壁纸已更新")
except Exception as e:
logger.exception("Refresh failed")
if self._icon and config.get("wallpaper.show_notification", True):
self._icon.notify(f"刷新失败: {e}")
def _on_auto_on(self, icon, item):
config.set_("auto_refresh.enabled", True)
self._start_auto_refresh()
icon.update_menu()
def _on_auto_off(self, icon, item):
config.set_("auto_refresh.enabled", False)
self._stop_auto_refresh()
icon.update_menu()
def _on_set_fill_style(self, icon, item):
for s in STYLES:
if STYLE_LABELS[s] == str(item):
config.set_("wallpaper.fill_style", s)
break
icon.update_menu()
def _on_toggle_notification(self, icon, item):
current = config.get("wallpaper.show_notification", True)
config.set_("wallpaper.show_notification", not current)
icon.update_menu()
def _on_install_menu(self, icon, item):
threading.Thread(target=self._do_install_menu, daemon=True).start()
def _do_install_menu(self):
try:
from install_menu import install
install()
if self._icon:
self._icon.notify("右键菜单已安装")
except Exception as e:
logger.exception("Install menu failed")
if self._icon:
self._icon.notify(f"安装失败: {e}")
def _on_uninstall_menu(self, icon, item):
threading.Thread(target=self._do_uninstall_menu, daemon=True).start()
def _do_uninstall_menu(self):
try:
from install_menu import uninstall
uninstall()
if self._icon:
self._icon.notify("右键菜单已卸载")
except Exception as e:
logger.exception("Uninstall menu failed")
if self._icon:
self._icon.notify(f"卸载失败: {e}")
def _on_exit(self, icon, item):
self.stop()
def _start_auto_refresh(self):
self._stop_auto_refresh()
interval = config.get("auto_refresh.interval_minutes", 10) * 60
self._auto_timer = threading.Timer(interval, self._auto_refresh_tick)
self._auto_timer.daemon = True
self._auto_timer.start()
logger.info("Auto refresh started, interval=%ds", interval)
def _stop_auto_refresh(self):
if self._auto_timer:
self._auto_timer.cancel()
self._auto_timer = None
def _auto_refresh_tick(self):
if not self._running:
return
self._do_refresh()
if config.get("auto_refresh.enabled"):
interval = config.get("auto_refresh.interval_minutes", 10) * 60
self._auto_timer = threading.Timer(interval, self._auto_refresh_tick)
self._auto_timer.daemon = True
self._auto_timer.start()