diff --git a/config/resources/arrow.png b/config/resources/arrow.png new file mode 100644 index 0000000..7949694 Binary files /dev/null and b/config/resources/arrow.png differ diff --git a/config/resources/backward.png b/config/resources/backward.png new file mode 100644 index 0000000..6b080cf Binary files /dev/null and b/config/resources/backward.png differ diff --git a/config/resources/exit.png b/config/resources/exit.png new file mode 100644 index 0000000..0c093f4 Binary files /dev/null and b/config/resources/exit.png differ diff --git a/config/resources/forward.png b/config/resources/forward.png new file mode 100644 index 0000000..d58221f Binary files /dev/null and b/config/resources/forward.png differ diff --git a/config/resources/pause.png b/config/resources/pause.png new file mode 100644 index 0000000..5e96c0c Binary files /dev/null and b/config/resources/pause.png differ diff --git a/config/resources/play.png b/config/resources/play.png new file mode 100644 index 0000000..8ef2422 Binary files /dev/null and b/config/resources/play.png differ diff --git a/config/resources/settings.png b/config/resources/settings.png new file mode 100644 index 0000000..b4271d7 Binary files /dev/null and b/config/resources/settings.png differ diff --git a/src/main.py b/src/main.py index b05d18d..6c4f584 100644 --- a/src/main.py +++ b/src/main.py @@ -18,6 +18,7 @@ from kivy.uix.popup import Popup from kivy.uix.textinput import TextInput from kivy.clock import Clock from kivy.core.window import Window +from kivy.properties import BooleanProperty from kivy.logger import Logger from kivy.animation import Animation from kivy.lang import Builder @@ -61,9 +62,20 @@ class SettingsPopup(Popup): 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): super(SignagePlayer, self).__init__(**kwargs) - # Initialize variables self.playlist = [] self.current_index = 0 @@ -72,27 +84,33 @@ class SignagePlayer(Widget): self.is_paused = False self.config = {} self.playlist_version = None - # Paths self.base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) self.config_dir = os.path.join(self.base_dir, 'config') self.media_dir = os.path.join(self.base_dir, 'media') self.playlists_dir = os.path.join(self.base_dir, 'playlists') 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 for directory in [self.config_dir, self.media_dir, self.playlists_dir]: 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 Clock.schedule_once(self.initialize_player, 0.1) - # Hide controls timer self.controls_timer = None - # Auto-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): """Initialize the player - load config and start playlist checking""" Logger.info("SignagePlayer: Initializing player...") @@ -311,15 +329,11 @@ class SignagePlayer(Widget): source=image_path, allow_stretch=True, keep_ratio=False, - size_hint=(1, 1), - pos_hint={'x': 0, 'y': 0} + size_hint=(1, 1) ) - self.ids.content_area.add_widget(self.current_widget) - # Schedule next media after duration Clock.schedule_once(self.next_media, duration) - except Exception as e: Logger.error(f"SignagePlayer: Error playing image {image_path}: {e}") self.next_media() @@ -436,17 +450,13 @@ class SignagePlayer(Widget): class SignagePlayerApp(App): 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: 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 Clock.schedule_once(self.hide_cursor, 3) - return SignagePlayer() def hide_cursor(self, dt): diff --git a/src/signage_player.kv b/src/signage_player.kv index 1d6f22d..19b28c2 100644 --- a/src/signage_player.kv +++ b/src/signage_player.kv @@ -1,25 +1,27 @@ #:kivy 2.1.0 -: +: + size: root.screen_width, root.screen_height canvas.before: Color: rgba: 0, 0, 0, 1 Rectangle: size: self.size pos: self.pos - - # Main content area - FULLSCREEN WIDGET - Widget: + + # Main content area for images/videos + FloatLayout: id: content_area - size_hint: 1, 1 + size: root.screen_width, root.screen_height + size_hint: None, None pos_hint: {'x': 0, 'y': 0} - - # Status label overlay (shown when no content or errors) + + # Status label overlay (centered) Label: id: status_label text: 'Loading...' - size_hint: None, None - size: dp(400), dp(60) + size_hint: 0.5, 0.5 + size: dp(600), dp(120) pos_hint: {'center_x': 0.5, 'center_y': 0.5} color: 1, 1, 1, 1 font_size: sp(18) @@ -33,110 +35,66 @@ size: self.size pos: self.pos radius: [dp(15)] - - # Control panel overlay (always on top) + + # Control panel overlay (bottom center, 5 columns, 1 row) BoxLayout: id: controls_layout orientation: 'horizontal' size_hint: None, None - size: dp(450), dp(60) - pos_hint: {'right': 0.98, 'top': 0.98} - opacity: 0 - spacing: dp(5) + size: dp(340), dp(70) + pos_hint: {'center_x': 0.5, 'y': 0.02} + opacity: 1 + spacing: dp(10) padding: dp(10) canvas.before: Color: - rgba: 0.1, 0.1, 0.1, 0.9 + rgba: 0.1, 0.1, 0.1, 0.9 # 90% transparent RoundedRectangle: size: self.size pos: self.pos - radius: [dp(15)] - - # Control buttons + radius: [dp(20)] Button: - id: prev_btn - text: '⏮' + id: backward_btn 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 + size: dp(60), dp(60) + background_normal: root.resources_path + '/backward.png' + background_down: root.resources_path + '/backward.png' + background_color: 1, 1, 1, 0 on_press: root.previous_media() - canvas.before: - Color: - rgba: self.background_color - RoundedRectangle: - size: self.size - pos: self.pos - radius: [dp(8)] - Button: id: play_pause_btn - text: '⏸' size_hint: None, None - size: dp(60), dp(50) - font_size: sp(18) - background_color: 0.2, 0.6, 0.2, 0.9 - color: 1, 1, 1, 1 + size: dp(60), dp(60) + background_normal: root.resources_path + '/play.png' + background_down: root.resources_path + '/pause.png' + background_color: 1, 1, 1, 0 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: id: settings_btn - text: '⚙' size_hint: None, None - size: dp(60), dp(50) - font_size: sp(18) - background_color: 0.4, 0.4, 0.2, 0.9 - color: 1, 1, 1, 1 + size: dp(60), dp(60) + background_normal: root.resources_path + '/settings.png' + background_down: root.resources_path + '/settings.png' + background_color: 1, 1, 1, 0 on_press: root.show_settings() - canvas.before: - Color: - rgba: self.background_color - RoundedRectangle: - size: self.size - pos: self.pos - radius: [dp(8)] - Button: id: exit_btn - text: '⏻' size_hint: None, None - size: dp(60), dp(50) - font_size: sp(18) - background_color: 0.6, 0.2, 0.2, 0.9 - color: 1, 1, 1, 1 - on_press: root.exit_app() - canvas.before: - Color: - rgba: self.background_color - RoundedRectangle: - size: self.size - pos: self.pos - radius: [dp(8)] + size: dp(60), dp(60) + background_normal: root.resources_path + '/exit.png' + background_down: root.resources_path + '/exit.png' + background_color: 1, 1, 1, 0 + on_press: app.stop() + Button: + id: forward_btn + size_hint: None, None + size: dp(60), dp(60) + background_normal: root.resources_path + '/forward.png' + background_down: root.resources_path + '/forward.png' + background_color: 1, 1, 1, 0 + on_press: root.next_media() + + # Settings popup content