update location and setting

This commit is contained in:
Kivy Signage Player
2025-09-30 10:36:30 +03:00
parent e052f4d068
commit 88b28a5937
9 changed files with 75 additions and 107 deletions

BIN
config/resources/arrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
config/resources/exit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
config/resources/pause.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
config/resources/play.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -18,6 +18,7 @@ from kivy.uix.popup import Popup
from kivy.uix.textinput import TextInput from kivy.uix.textinput import TextInput
from kivy.clock import Clock from kivy.clock import Clock
from kivy.core.window import Window from kivy.core.window import Window
from kivy.properties import BooleanProperty
from kivy.logger import Logger from kivy.logger import Logger
from kivy.animation import Animation from kivy.animation import Animation
from kivy.lang import Builder from kivy.lang import Builder
@@ -61,9 +62,20 @@ class SettingsPopup(Popup):
class SignagePlayer(Widget): class SignagePlayer(Widget):
from kivy.properties import StringProperty
resources_path = StringProperty()
from kivy.properties import NumericProperty
screen_width = NumericProperty(0)
screen_height = NumericProperty(0)
def set_screen_size(self):
"""Get the current screen size and set as properties."""
self.screen_width, self.screen_height = Window.size
Logger.info(f"Screen size detected: {self.screen_width}x{self.screen_height}")
is_paused = BooleanProperty(False)
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(SignagePlayer, self).__init__(**kwargs) super(SignagePlayer, self).__init__(**kwargs)
# Initialize variables # Initialize variables
self.playlist = [] self.playlist = []
self.current_index = 0 self.current_index = 0
@@ -72,27 +84,33 @@ class SignagePlayer(Widget):
self.is_paused = False self.is_paused = False
self.config = {} self.config = {}
self.playlist_version = None self.playlist_version = None
# Paths # Paths
self.base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) self.base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
self.config_dir = os.path.join(self.base_dir, 'config') self.config_dir = os.path.join(self.base_dir, 'config')
self.media_dir = os.path.join(self.base_dir, 'media') self.media_dir = os.path.join(self.base_dir, 'media')
self.playlists_dir = os.path.join(self.base_dir, 'playlists') self.playlists_dir = os.path.join(self.base_dir, 'playlists')
self.config_file = os.path.join(self.config_dir, 'app_config.json') self.config_file = os.path.join(self.config_dir, 'app_config.json')
self.resources_path = os.path.join(self.config_dir, 'resources')
# Create directories if they don't exist # Create directories if they don't exist
for directory in [self.config_dir, self.media_dir, self.playlists_dir]: for directory in [self.config_dir, self.media_dir, self.playlists_dir]:
os.makedirs(directory, exist_ok=True) os.makedirs(directory, exist_ok=True)
# Get and set screen size
self.set_screen_size()
# Bind to window size for fullscreen
Window.bind(size=self._update_size)
self._update_size(Window, Window.size)
# Initialize player # Initialize player
Clock.schedule_once(self.initialize_player, 0.1) Clock.schedule_once(self.initialize_player, 0.1)
# Hide controls timer # Hide controls timer
self.controls_timer = None self.controls_timer = None
# Auto-hide controls # Auto-hide controls
self.schedule_hide_controls() self.schedule_hide_controls()
def _update_size(self, instance, value):
self.size = value
if hasattr(self, 'ids') and 'content_area' in self.ids:
self.ids.content_area.size = value
def initialize_player(self, dt): def initialize_player(self, dt):
"""Initialize the player - load config and start playlist checking""" """Initialize the player - load config and start playlist checking"""
Logger.info("SignagePlayer: Initializing player...") Logger.info("SignagePlayer: Initializing player...")
@@ -311,15 +329,11 @@ class SignagePlayer(Widget):
source=image_path, source=image_path,
allow_stretch=True, allow_stretch=True,
keep_ratio=False, keep_ratio=False,
size_hint=(1, 1), size_hint=(1, 1)
pos_hint={'x': 0, 'y': 0}
) )
self.ids.content_area.add_widget(self.current_widget) self.ids.content_area.add_widget(self.current_widget)
# Schedule next media after duration # Schedule next media after duration
Clock.schedule_once(self.next_media, duration) Clock.schedule_once(self.next_media, duration)
except Exception as e: except Exception as e:
Logger.error(f"SignagePlayer: Error playing image {image_path}: {e}") Logger.error(f"SignagePlayer: Error playing image {image_path}: {e}")
self.next_media() self.next_media()
@@ -436,17 +450,13 @@ class SignagePlayer(Widget):
class SignagePlayerApp(App): class SignagePlayerApp(App):
def build(self): def build(self):
# Get screen resolution info # Force fullscreen and borderless
Window.fullscreen = True
Window.borderless = True
Logger.info(f"SignagePlayerApp: Screen size: {Window.size}") Logger.info(f"SignagePlayerApp: Screen size: {Window.size}")
Logger.info(f"SignagePlayerApp: Available screen size: {Window.system_size if hasattr(Window, 'system_size') else 'N/A'}") Logger.info(f"SignagePlayerApp: Available screen size: {Window.system_size if hasattr(Window, 'system_size') else 'N/A'}")
# Set window to fullscreen and borderless
Window.fullscreen = 'auto'
Window.borderless = True
# Hide cursor after 3 seconds of inactivity # Hide cursor after 3 seconds of inactivity
Clock.schedule_once(self.hide_cursor, 3) Clock.schedule_once(self.hide_cursor, 3)
return SignagePlayer() return SignagePlayer()
def hide_cursor(self, dt): def hide_cursor(self, dt):

View File

@@ -1,25 +1,27 @@
#:kivy 2.1.0 #:kivy 2.1.0
<SignagePlayer>: <SignagePlayer@FloatLayout>:
size: root.screen_width, root.screen_height
canvas.before: canvas.before:
Color: Color:
rgba: 0, 0, 0, 1 rgba: 0, 0, 0, 1
Rectangle: Rectangle:
size: self.size size: self.size
pos: self.pos pos: self.pos
# Main content area - FULLSCREEN WIDGET # Main content area for images/videos
Widget: FloatLayout:
id: content_area id: content_area
size_hint: 1, 1 size: root.screen_width, root.screen_height
size_hint: None, None
pos_hint: {'x': 0, 'y': 0} pos_hint: {'x': 0, 'y': 0}
# Status label overlay (shown when no content or errors) # Status label overlay (centered)
Label: Label:
id: status_label id: status_label
text: 'Loading...' text: 'Loading...'
size_hint: None, None size_hint: 0.5, 0.5
size: dp(400), dp(60) size: dp(600), dp(120)
pos_hint: {'center_x': 0.5, 'center_y': 0.5} pos_hint: {'center_x': 0.5, 'center_y': 0.5}
color: 1, 1, 1, 1 color: 1, 1, 1, 1
font_size: sp(18) font_size: sp(18)
@@ -33,110 +35,66 @@
size: self.size size: self.size
pos: self.pos pos: self.pos
radius: [dp(15)] radius: [dp(15)]
# Control panel overlay (always on top) # Control panel overlay (bottom center, 5 columns, 1 row)
BoxLayout: BoxLayout:
id: controls_layout id: controls_layout
orientation: 'horizontal' orientation: 'horizontal'
size_hint: None, None size_hint: None, None
size: dp(450), dp(60) size: dp(340), dp(70)
pos_hint: {'right': 0.98, 'top': 0.98} pos_hint: {'center_x': 0.5, 'y': 0.02}
opacity: 0 opacity: 1
spacing: dp(5) spacing: dp(10)
padding: dp(10) padding: dp(10)
canvas.before: canvas.before:
Color: Color:
rgba: 0.1, 0.1, 0.1, 0.9 rgba: 0.1, 0.1, 0.1, 0.9 # 90% transparent
RoundedRectangle: RoundedRectangle:
size: self.size size: self.size
pos: self.pos pos: self.pos
radius: [dp(15)] radius: [dp(20)]
# Control buttons
Button: Button:
id: prev_btn id: backward_btn
text: '⏮'
size_hint: None, None size_hint: None, None
size: dp(60), dp(50) size: dp(60), dp(60)
font_size: sp(18) background_normal: root.resources_path + '/backward.png'
background_color: 0.2, 0.2, 0.2, 0.9 background_down: root.resources_path + '/backward.png'
color: 1, 1, 1, 1 background_color: 1, 1, 1, 0
on_press: root.previous_media() on_press: root.previous_media()
canvas.before:
Color:
rgba: self.background_color
RoundedRectangle:
size: self.size
pos: self.pos
radius: [dp(8)]
Button: Button:
id: play_pause_btn id: play_pause_btn
text: '⏸'
size_hint: None, None size_hint: None, None
size: dp(60), dp(50) size: dp(60), dp(60)
font_size: sp(18) background_normal: root.resources_path + '/play.png'
background_color: 0.2, 0.6, 0.2, 0.9 background_down: root.resources_path + '/pause.png'
color: 1, 1, 1, 1 background_color: 1, 1, 1, 0
on_press: root.toggle_pause() on_press: root.toggle_pause()
canvas.before:
Color:
rgba: self.background_color
RoundedRectangle:
size: self.size
pos: self.pos
radius: [dp(8)]
Button:
id: next_btn
text: '⏭'
size_hint: None, None
size: dp(60), dp(50)
font_size: sp(18)
background_color: 0.2, 0.2, 0.2, 0.9
color: 1, 1, 1, 1
on_press: root.next_media()
canvas.before:
Color:
rgba: self.background_color
RoundedRectangle:
size: self.size
pos: self.pos
radius: [dp(8)]
Button: Button:
id: settings_btn id: settings_btn
text: '⚙'
size_hint: None, None size_hint: None, None
size: dp(60), dp(50) size: dp(60), dp(60)
font_size: sp(18) background_normal: root.resources_path + '/settings.png'
background_color: 0.4, 0.4, 0.2, 0.9 background_down: root.resources_path + '/settings.png'
color: 1, 1, 1, 1 background_color: 1, 1, 1, 0
on_press: root.show_settings() on_press: root.show_settings()
canvas.before:
Color:
rgba: self.background_color
RoundedRectangle:
size: self.size
pos: self.pos
radius: [dp(8)]
Button: Button:
id: exit_btn id: exit_btn
text: '⏻'
size_hint: None, None size_hint: None, None
size: dp(60), dp(50) size: dp(60), dp(60)
font_size: sp(18) background_normal: root.resources_path + '/exit.png'
background_color: 0.6, 0.2, 0.2, 0.9 background_down: root.resources_path + '/exit.png'
color: 1, 1, 1, 1 background_color: 1, 1, 1, 0
on_press: root.exit_app() on_press: app.stop()
canvas.before: Button:
Color: id: forward_btn
rgba: self.background_color size_hint: None, None
RoundedRectangle: size: dp(60), dp(60)
size: self.size background_normal: root.resources_path + '/forward.png'
pos: self.pos background_down: root.resources_path + '/forward.png'
radius: [dp(8)] background_color: 1, 1, 1, 0
on_press: root.next_media()
# Settings popup content # Settings popup content