UI/UX: Improved mouse hiding logic, overlay controls, and robust player integration
This commit is contained in:
Binary file not shown.
90
signage_player/appsettings.py
Normal file
90
signage_player/appsettings.py
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
import tkinter as tk
|
||||||
|
from tkinter import ttk, messagebox
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
CONFIG_PATH = os.path.join(os.path.dirname(__file__), 'main_data', 'app_config.txt')
|
||||||
|
|
||||||
|
class AppSettingsWindow(tk.Tk):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.title('App Settings')
|
||||||
|
self.geometry('440x600') # Increased height for better button visibility
|
||||||
|
self.resizable(False, False)
|
||||||
|
self.config(bg='#23272e')
|
||||||
|
self.fields = {}
|
||||||
|
self.load_config()
|
||||||
|
self.style = ttk.Style(self)
|
||||||
|
self.set_styles()
|
||||||
|
self.create_widgets()
|
||||||
|
|
||||||
|
def set_styles(self):
|
||||||
|
self.style.theme_use('clam')
|
||||||
|
self.style.configure('TLabel', background='#23272e', foreground='#e0e0e0', font=('Segoe UI', 13, 'bold'))
|
||||||
|
self.style.configure('TEntry', fieldbackground='#2c313c', foreground='#e0e0e0', borderwidth=1, relief='flat', font=('Segoe UI', 12))
|
||||||
|
self.style.map('TEntry', fieldbackground=[('active', '#23272e')])
|
||||||
|
self.style.configure('TButton', background='#3b82f6', foreground='white', font=('Segoe UI', 13, 'bold'), borderwidth=0, focusthickness=3, focuscolor='#60a5fa', padding=8)
|
||||||
|
self.style.map('TButton', background=[('active', '#2563eb')])
|
||||||
|
|
||||||
|
def load_config(self):
|
||||||
|
try:
|
||||||
|
with open(CONFIG_PATH, 'r') as f:
|
||||||
|
self.config_data = json.load(f)
|
||||||
|
except Exception as e:
|
||||||
|
self.config_data = {}
|
||||||
|
messagebox.showerror('Error', f'Failed to load config: {e}')
|
||||||
|
|
||||||
|
def save_config(self):
|
||||||
|
try:
|
||||||
|
for key, entry in self.fields.items():
|
||||||
|
if hasattr(entry, 'get'):
|
||||||
|
self.config_data[key] = entry.get()
|
||||||
|
with open(CONFIG_PATH, 'w') as f:
|
||||||
|
json.dump(self.config_data, f, indent=4)
|
||||||
|
self.show_custom_popup('Success', 'Settings saved!')
|
||||||
|
except Exception as e:
|
||||||
|
messagebox.showerror('Error', f'Failed to save config: {e}')
|
||||||
|
|
||||||
|
def show_custom_popup(self, title, message):
|
||||||
|
popup = tk.Toplevel(self)
|
||||||
|
popup.title(title)
|
||||||
|
popup.geometry('320x120')
|
||||||
|
popup.configure(bg='#23272e')
|
||||||
|
popup.resizable(False, False)
|
||||||
|
popup.attributes('-topmost', True)
|
||||||
|
ttk.Label(popup, text=title, style='TLabel').pack(pady=(18, 0))
|
||||||
|
ttk.Label(popup, text=message, style='TLabel').pack(pady=(8, 0))
|
||||||
|
close_btn = ttk.Button(popup, text='OK', style='TButton', command=popup.destroy)
|
||||||
|
close_btn.pack(pady=18)
|
||||||
|
popup.grab_set()
|
||||||
|
popup.after(5000, popup.destroy)
|
||||||
|
|
||||||
|
def create_widgets(self):
|
||||||
|
title = ttk.Label(self, text='Application Settings', style='TLabel')
|
||||||
|
title.grid(row=0, column=0, columnspan=2, pady=(18, 6))
|
||||||
|
warning = tk.Label(self, text='⚠️ Modify values only if necessary or instructed!', fg='#ffb300', bg='#23272e', font=('Segoe UI', 11, 'bold'))
|
||||||
|
warning.grid(row=1, column=0, columnspan=2, pady=(0, 18))
|
||||||
|
row = 2
|
||||||
|
for key, value in self.config_data.items():
|
||||||
|
label = ttk.Label(self, text=key+':', style='TLabel')
|
||||||
|
label.grid(row=row, column=0, sticky='e', padx=18, pady=10)
|
||||||
|
if key == 'touch_screen':
|
||||||
|
var = tk.StringVar()
|
||||||
|
combo = ttk.Combobox(self, textvariable=var, values=['On', 'Off'], state='readonly', width=26)
|
||||||
|
combo.set(str(value))
|
||||||
|
combo.grid(row=row, column=1, padx=10, pady=10)
|
||||||
|
self.fields[key] = combo
|
||||||
|
else:
|
||||||
|
entry = ttk.Entry(self, style='TEntry', width=28)
|
||||||
|
entry.insert(0, str(value))
|
||||||
|
entry.grid(row=row, column=1, padx=10, pady=10)
|
||||||
|
self.fields[key] = entry
|
||||||
|
row += 1
|
||||||
|
save_btn = ttk.Button(self, text='Save Settings', style='TButton', command=self.save_config)
|
||||||
|
save_btn.grid(row=row, column=0, pady=30, sticky='e', padx=(0,10))
|
||||||
|
close_btn = ttk.Button(self, text='Close', style='TButton', command=self.destroy)
|
||||||
|
close_btn.grid(row=row, column=1, pady=30, sticky='w', padx=(10,0))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app = AppSettingsWindow()
|
||||||
|
app.mainloop()
|
||||||
@@ -6,5 +6,6 @@
|
|||||||
"port": "80",
|
"port": "80",
|
||||||
"screen_w": "1920",
|
"screen_w": "1920",
|
||||||
"screen_h": "1080",
|
"screen_h": "1080",
|
||||||
"refresh_time": "5"
|
"refresh_time": "5",
|
||||||
}
|
"touch_screen": "On"
|
||||||
|
}
|
||||||
@@ -193,3 +193,43 @@
|
|||||||
[INFO] [SignageApp] File call-of-duty-black-3840x2160-23674.jpg already exists. Skipping download.
|
[INFO] [SignageApp] File call-of-duty-black-3840x2160-23674.jpg already exists. Skipping download.
|
||||||
[INFO] [SignageApp] Preparing to download demo2.jpeg from http://192.168.1.22/media/demo2.jpeg...
|
[INFO] [SignageApp] Preparing to download demo2.jpeg from http://192.168.1.22/media/demo2.jpeg...
|
||||||
[INFO] [SignageApp] File demo2.jpeg already exists. Skipping download.
|
[INFO] [SignageApp] File demo2.jpeg already exists. Skipping download.
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://192.168.1.22:80/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$4dxmxuyiezoojRSThjmzQeVsaBscU5vP.9GcTPJhXymmL9JsNklea', 'playlist': [{'duration': 30, 'file_name': 'big-buck-bunny-1080p-60fps-30sec.mp4', 'url': 'http://192.168.1.22/media/big-buck-bunny-1080p-60fps-30sec.mp4'}, {'duration': 10, 'file_name': 'call-of-duty-black-3840x2160-23674.jpg', 'url': 'http://192.168.1.22/media/call-of-duty-black-3840x2160-23674.jpg'}, {'duration': 10, 'file_name': 'demo2.jpeg', 'url': 'http://192.168.1.22/media/demo2.jpeg'}], 'playlist_version': 4}
|
||||||
|
[INFO] [SignageApp] Fetched updated playlist from server.
|
||||||
|
[INFO] [SignageApp] Local playlist version: 0, Server playlist version: 4
|
||||||
|
[INFO] [SignageApp] Preparing to download big-buck-bunny-1080p-60fps-30sec.mp4 from http://192.168.1.22/media/big-buck-bunny-1080p-60fps-30sec.mp4...
|
||||||
|
[INFO] [SignageApp] File big-buck-bunny-1080p-60fps-30sec.mp4 already exists. Skipping download.
|
||||||
|
[INFO] [SignageApp] Preparing to download call-of-duty-black-3840x2160-23674.jpg from http://192.168.1.22/media/call-of-duty-black-3840x2160-23674.jpg...
|
||||||
|
[INFO] [SignageApp] File call-of-duty-black-3840x2160-23674.jpg already exists. Skipping download.
|
||||||
|
[INFO] [SignageApp] Preparing to download demo2.jpeg from http://192.168.1.22/media/demo2.jpeg...
|
||||||
|
[INFO] [SignageApp] File demo2.jpeg already exists. Skipping download.
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://192.168.1.22:80/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$4dxmxuyiezoojRSThjmzQeVsaBscU5vP.9GcTPJhXymmL9JsNklea', 'playlist': [{'duration': 30, 'file_name': 'big-buck-bunny-1080p-60fps-30sec.mp4', 'url': 'http://192.168.1.22/media/big-buck-bunny-1080p-60fps-30sec.mp4'}, {'duration': 10, 'file_name': 'call-of-duty-black-3840x2160-23674.jpg', 'url': 'http://192.168.1.22/media/call-of-duty-black-3840x2160-23674.jpg'}, {'duration': 10, 'file_name': 'demo2.jpeg', 'url': 'http://192.168.1.22/media/demo2.jpeg'}], 'playlist_version': 4}
|
||||||
|
[INFO] [SignageApp] Fetched updated playlist from server.
|
||||||
|
[INFO] [SignageApp] Local playlist version: 0, Server playlist version: 4
|
||||||
|
[INFO] [SignageApp] Preparing to download big-buck-bunny-1080p-60fps-30sec.mp4 from http://192.168.1.22/media/big-buck-bunny-1080p-60fps-30sec.mp4...
|
||||||
|
[INFO] [SignageApp] File big-buck-bunny-1080p-60fps-30sec.mp4 already exists. Skipping download.
|
||||||
|
[INFO] [SignageApp] Preparing to download call-of-duty-black-3840x2160-23674.jpg from http://192.168.1.22/media/call-of-duty-black-3840x2160-23674.jpg...
|
||||||
|
[INFO] [SignageApp] File call-of-duty-black-3840x2160-23674.jpg already exists. Skipping download.
|
||||||
|
[INFO] [SignageApp] Preparing to download demo2.jpeg from http://192.168.1.22/media/demo2.jpeg...
|
||||||
|
[INFO] [SignageApp] File demo2.jpeg already exists. Skipping download.
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://192.168.1.22:80/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$4dxmxuyiezoojRSThjmzQeVsaBscU5vP.9GcTPJhXymmL9JsNklea', 'playlist': [{'duration': 30, 'file_name': 'big-buck-bunny-1080p-60fps-30sec.mp4', 'url': 'http://192.168.1.22/media/big-buck-bunny-1080p-60fps-30sec.mp4'}, {'duration': 10, 'file_name': 'call-of-duty-black-3840x2160-23674.jpg', 'url': 'http://192.168.1.22/media/call-of-duty-black-3840x2160-23674.jpg'}, {'duration': 10, 'file_name': 'demo2.jpeg', 'url': 'http://192.168.1.22/media/demo2.jpeg'}], 'playlist_version': 4}
|
||||||
|
[INFO] [SignageApp] Fetched updated playlist from server.
|
||||||
|
[INFO] [SignageApp] Local playlist version: 0, Server playlist version: 4
|
||||||
|
[INFO] [SignageApp] Preparing to download big-buck-bunny-1080p-60fps-30sec.mp4 from http://192.168.1.22/media/big-buck-bunny-1080p-60fps-30sec.mp4...
|
||||||
|
[INFO] [SignageApp] File big-buck-bunny-1080p-60fps-30sec.mp4 already exists. Skipping download.
|
||||||
|
[INFO] [SignageApp] Preparing to download call-of-duty-black-3840x2160-23674.jpg from http://192.168.1.22/media/call-of-duty-black-3840x2160-23674.jpg...
|
||||||
|
[INFO] [SignageApp] File call-of-duty-black-3840x2160-23674.jpg already exists. Skipping download.
|
||||||
|
[INFO] [SignageApp] Preparing to download demo2.jpeg from http://192.168.1.22/media/demo2.jpeg...
|
||||||
|
[INFO] [SignageApp] File demo2.jpeg already exists. Skipping download.
|
||||||
|
[INFO] [SignageApp] Fetching playlist from URL: http://192.168.1.22:80/api/playlists with params: {'hostname': 'tv-terasa', 'quickconnect_code': '8887779'}
|
||||||
|
[INFO] [SignageApp] Server response: {'hashed_quickconnect': '$2b$12$4dxmxuyiezoojRSThjmzQeVsaBscU5vP.9GcTPJhXymmL9JsNklea', 'playlist': [{'duration': 30, 'file_name': 'big-buck-bunny-1080p-60fps-30sec.mp4', 'url': 'http://192.168.1.22/media/big-buck-bunny-1080p-60fps-30sec.mp4'}, {'duration': 10, 'file_name': 'call-of-duty-black-3840x2160-23674.jpg', 'url': 'http://192.168.1.22/media/call-of-duty-black-3840x2160-23674.jpg'}, {'duration': 10, 'file_name': 'demo2.jpeg', 'url': 'http://192.168.1.22/media/demo2.jpeg'}], 'playlist_version': 4}
|
||||||
|
[INFO] [SignageApp] Fetched updated playlist from server.
|
||||||
|
[INFO] [SignageApp] Local playlist version: 0, Server playlist version: 4
|
||||||
|
[INFO] [SignageApp] Preparing to download big-buck-bunny-1080p-60fps-30sec.mp4 from http://192.168.1.22/media/big-buck-bunny-1080p-60fps-30sec.mp4...
|
||||||
|
[INFO] [SignageApp] File big-buck-bunny-1080p-60fps-30sec.mp4 already exists. Skipping download.
|
||||||
|
[INFO] [SignageApp] Preparing to download call-of-duty-black-3840x2160-23674.jpg from http://192.168.1.22/media/call-of-duty-black-3840x2160-23674.jpg...
|
||||||
|
[INFO] [SignageApp] File call-of-duty-black-3840x2160-23674.jpg already exists. Skipping download.
|
||||||
|
[INFO] [SignageApp] Preparing to download demo2.jpeg from http://192.168.1.22/media/demo2.jpeg...
|
||||||
|
[INFO] [SignageApp] File demo2.jpeg already exists. Skipping download.
|
||||||
|
|||||||
@@ -79,9 +79,13 @@ class SimpleTkPlayer:
|
|||||||
|
|
||||||
def hide_mouse(self):
|
def hide_mouse(self):
|
||||||
self.root.config(cursor='none')
|
self.root.config(cursor='none')
|
||||||
|
if hasattr(self, 'controls_win'):
|
||||||
|
self.controls_win.config(cursor='none')
|
||||||
|
|
||||||
def show_mouse(self):
|
def show_mouse(self):
|
||||||
self.root.config(cursor='arrow')
|
self.root.config(cursor='arrow')
|
||||||
|
if hasattr(self, 'controls_win'):
|
||||||
|
self.controls_win.config(cursor='arrow')
|
||||||
|
|
||||||
def move_mouse_to_corner(self):
|
def move_mouse_to_corner(self):
|
||||||
try:
|
try:
|
||||||
@@ -232,20 +236,18 @@ class SimpleTkPlayer:
|
|||||||
if self.paused is not True:
|
if self.paused is not True:
|
||||||
self.paused = True
|
self.paused = True
|
||||||
self.pause_btn.config(text='▶ Resume')
|
self.pause_btn.config(text='▶ Resume')
|
||||||
settings_win = tk.Toplevel(self.root)
|
import subprocess, sys
|
||||||
settings_win.title('Settings')
|
settings_path = os.path.join(os.path.dirname(__file__), 'appsettings.py')
|
||||||
settings_win.geometry('400x300+100+100')
|
# Open settings in a new process so it doesn't block the main player
|
||||||
settings_win.transient(self.root)
|
proc = subprocess.Popen([sys.executable, settings_path])
|
||||||
settings_win.grab_set()
|
# Wait for the settings window to close, then resume
|
||||||
tk.Label(settings_win, text='Settings', font=('Arial', 18)).pack(pady=10)
|
self.root.after(1000, lambda: self.check_settings_closed(proc))
|
||||||
# Example setting: close button
|
|
||||||
tk.Button(settings_win, text='Close', command=settings_win.destroy).pack(pady=20)
|
def check_settings_closed(self, proc):
|
||||||
def on_close():
|
if proc.poll() is not None:
|
||||||
settings_win.grab_release()
|
|
||||||
settings_win.destroy()
|
|
||||||
self.resume_play()
|
self.resume_play()
|
||||||
settings_win.protocol('WM_DELETE_WINDOW', on_close)
|
else:
|
||||||
settings_win.bind('<Destroy>', lambda e: self.resume_play() if not settings_win.winfo_exists() else None)
|
self.root.after(1000, lambda: self.check_settings_closed(proc))
|
||||||
|
|
||||||
def main_start(self):
|
def main_start(self):
|
||||||
self.play_intro_video()
|
self.play_intro_video()
|
||||||
|
|||||||
Reference in New Issue
Block a user