feat: add Restart and Shutdown tray actions with confirmation dialogs
This commit is contained in:
+35
-2
@@ -4,6 +4,8 @@ import io
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import signal
|
import signal
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
|
||||||
@@ -17,6 +19,26 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
pystray = None
|
pystray = None
|
||||||
|
|
||||||
|
# tkinter is optional — used for confirmation dialogs
|
||||||
|
try:
|
||||||
|
import tkinter as tk
|
||||||
|
from tkinter import messagebox
|
||||||
|
except ImportError:
|
||||||
|
tk = None
|
||||||
|
messagebox = None
|
||||||
|
|
||||||
|
|
||||||
|
def _confirm(title: str, message: str) -> bool:
|
||||||
|
"""Show a Yes/No confirmation dialog. Returns True if user clicks Yes."""
|
||||||
|
if messagebox is None:
|
||||||
|
return True # No tkinter — skip confirmation
|
||||||
|
root = tk.Tk()
|
||||||
|
root.withdraw()
|
||||||
|
root.attributes("-topmost", True)
|
||||||
|
result = messagebox.askyesno(title, message, parent=root)
|
||||||
|
root.destroy()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def _create_icon_image(size: int = 64) -> Image.Image:
|
def _create_icon_image(size: int = 64) -> Image.Image:
|
||||||
"""Create a tray icon: green circle with white play triangle."""
|
"""Create a tray icon: green circle with white play triangle."""
|
||||||
@@ -75,16 +97,27 @@ def start_tray(host: str, port: int) -> "pystray.Icon | None":
|
|||||||
def on_show_ui(_icon, _item):
|
def on_show_ui(_icon, _item):
|
||||||
webbrowser.open(url)
|
webbrowser.open(url)
|
||||||
|
|
||||||
|
def on_restart(_icon, _item):
|
||||||
|
if not _confirm("Restart Media Server", "Are you sure you want to restart the server?"):
|
||||||
|
return
|
||||||
|
logger.info("Restart requested from tray")
|
||||||
|
_icon.stop()
|
||||||
|
# Re-launch the same process, then exit current
|
||||||
|
subprocess.Popen([sys.executable] + sys.argv)
|
||||||
|
os.kill(os.getpid(), signal.SIGINT)
|
||||||
|
|
||||||
def on_exit(_icon, _item):
|
def on_exit(_icon, _item):
|
||||||
|
if not _confirm("Exit Media Server", "Are you sure you want to shut down the server?"):
|
||||||
|
return
|
||||||
logger.info("Exit requested from tray")
|
logger.info("Exit requested from tray")
|
||||||
_icon.stop()
|
_icon.stop()
|
||||||
# Signal the main process to shut down gracefully
|
|
||||||
os.kill(os.getpid(), signal.SIGINT)
|
os.kill(os.getpid(), signal.SIGINT)
|
||||||
|
|
||||||
menu = pystray.Menu(
|
menu = pystray.Menu(
|
||||||
pystray.MenuItem("Show UI", on_show_ui, default=True),
|
pystray.MenuItem("Show UI", on_show_ui, default=True),
|
||||||
pystray.Menu.SEPARATOR,
|
pystray.Menu.SEPARATOR,
|
||||||
pystray.MenuItem("Exit", on_exit),
|
pystray.MenuItem("Restart", on_restart),
|
||||||
|
pystray.MenuItem("Shutdown", on_exit),
|
||||||
)
|
)
|
||||||
|
|
||||||
icon = pystray.Icon(
|
icon = pystray.Icon(
|
||||||
|
|||||||
Reference in New Issue
Block a user