Initial commit: Kivy Signage Player
- Complete Kivy-based signage player application - Fetches playlists from DigiServer via REST API - Supports images (JPG, PNG, GIF, BMP) and videos (MP4, AVI, MKV, MOV, WEBM) - Modern UI with touch controls and settings popup - Separated UI (KV file) from business logic (Python) - Fullscreen media display with proper scaling - Server feedback system for player status reporting - Auto-hide controls with mouse/touch activation - Virtual environment setup with requirements.txt - Installation and run scripts included Features: ✅ Cross-platform Kivy framework ✅ Server integration with DigiServer ✅ Media playback with duration control ✅ Player feedback and status reporting ✅ Settings management with persistent config ✅ Error handling and recovery ✅ Clean architecture with KV file separation
This commit is contained in:
229
src/signage_player.kv
Normal file
229
src/signage_player.kv
Normal file
@@ -0,0 +1,229 @@
|
||||
#:kivy 2.1.0
|
||||
|
||||
<SignagePlayer>:
|
||||
canvas.before:
|
||||
Color:
|
||||
rgba: 0, 0, 0, 1
|
||||
Rectangle:
|
||||
size: self.size
|
||||
pos: self.pos
|
||||
|
||||
# Main content area
|
||||
BoxLayout:
|
||||
id: main_layout
|
||||
orientation: 'vertical'
|
||||
|
||||
# Content display area (will be dynamically populated)
|
||||
Widget:
|
||||
id: content_area
|
||||
size_hint: 1, 1
|
||||
|
||||
# Status label (shown when no content or errors)
|
||||
Label:
|
||||
id: status_label
|
||||
text: 'Loading...'
|
||||
size_hint: 1, None
|
||||
height: dp(40)
|
||||
pos_hint: {'center_x': 0.5}
|
||||
color: 1, 1, 1, 1
|
||||
font_size: sp(16)
|
||||
text_size: self.size
|
||||
halign: 'center'
|
||||
valign: 'middle'
|
||||
|
||||
# Control panel overlay
|
||||
FloatLayout:
|
||||
id: overlay_layout
|
||||
size_hint: 1, 1
|
||||
|
||||
# Controls container
|
||||
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)
|
||||
padding: dp(10)
|
||||
canvas.before:
|
||||
Color:
|
||||
rgba: 0.1, 0.1, 0.1, 0.8
|
||||
RoundedRectangle:
|
||||
size: self.size
|
||||
pos: self.pos
|
||||
radius: [dp(10)]
|
||||
|
||||
# Control buttons
|
||||
Button:
|
||||
id: prev_btn
|
||||
text: '⏮'
|
||||
size_hint: None, None
|
||||
size: dp(60), dp(50)
|
||||
font_size: sp(18)
|
||||
background_color: 0.2, 0.2, 0.2, 1
|
||||
color: 1, 1, 1, 1
|
||||
on_press: root.previous_media()
|
||||
|
||||
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, 1
|
||||
color: 1, 1, 1, 1
|
||||
on_press: root.toggle_pause()
|
||||
|
||||
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, 1
|
||||
color: 1, 1, 1, 1
|
||||
on_press: root.next_media()
|
||||
|
||||
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, 1
|
||||
color: 1, 1, 1, 1
|
||||
on_press: root.show_settings()
|
||||
|
||||
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, 1
|
||||
color: 1, 1, 1, 1
|
||||
on_press: root.exit_app()
|
||||
|
||||
|
||||
# Settings popup content
|
||||
<SettingsPopup@Popup>:
|
||||
title: 'Player Settings'
|
||||
size_hint: 0.8, 0.8
|
||||
auto_dismiss: True
|
||||
|
||||
BoxLayout:
|
||||
orientation: 'vertical'
|
||||
padding: dp(20)
|
||||
spacing: dp(15)
|
||||
|
||||
# Server configuration
|
||||
BoxLayout:
|
||||
orientation: 'horizontal'
|
||||
size_hint_y: None
|
||||
height: dp(40)
|
||||
spacing: dp(10)
|
||||
|
||||
Label:
|
||||
text: 'Server IP:'
|
||||
size_hint_x: 0.3
|
||||
text_size: self.size
|
||||
halign: 'left'
|
||||
valign: 'middle'
|
||||
|
||||
TextInput:
|
||||
id: server_input
|
||||
size_hint_x: 0.7
|
||||
multiline: False
|
||||
font_size: sp(14)
|
||||
|
||||
# Screen name
|
||||
BoxLayout:
|
||||
orientation: 'horizontal'
|
||||
size_hint_y: None
|
||||
height: dp(40)
|
||||
spacing: dp(10)
|
||||
|
||||
Label:
|
||||
text: 'Screen Name:'
|
||||
size_hint_x: 0.3
|
||||
text_size: self.size
|
||||
halign: 'left'
|
||||
valign: 'middle'
|
||||
|
||||
TextInput:
|
||||
id: screen_input
|
||||
size_hint_x: 0.7
|
||||
multiline: False
|
||||
font_size: sp(14)
|
||||
|
||||
# Quickconnect key
|
||||
BoxLayout:
|
||||
orientation: 'horizontal'
|
||||
size_hint_y: None
|
||||
height: dp(40)
|
||||
spacing: dp(10)
|
||||
|
||||
Label:
|
||||
text: 'Quickconnect:'
|
||||
size_hint_x: 0.3
|
||||
text_size: self.size
|
||||
halign: 'left'
|
||||
valign: 'middle'
|
||||
|
||||
TextInput:
|
||||
id: quickconnect_input
|
||||
size_hint_x: 0.7
|
||||
multiline: False
|
||||
font_size: sp(14)
|
||||
|
||||
Widget:
|
||||
size_hint_y: 0.1
|
||||
|
||||
# Status information
|
||||
Label:
|
||||
id: playlist_info
|
||||
text: 'Playlist Version: N/A'
|
||||
size_hint_y: None
|
||||
height: dp(30)
|
||||
text_size: self.size
|
||||
halign: 'left'
|
||||
valign: 'middle'
|
||||
|
||||
Label:
|
||||
id: media_count_info
|
||||
text: 'Media Count: 0'
|
||||
size_hint_y: None
|
||||
height: dp(30)
|
||||
text_size: self.size
|
||||
halign: 'left'
|
||||
valign: 'middle'
|
||||
|
||||
Label:
|
||||
id: status_info
|
||||
text: 'Status: Idle'
|
||||
size_hint_y: None
|
||||
height: dp(30)
|
||||
text_size: self.size
|
||||
halign: 'left'
|
||||
valign: 'middle'
|
||||
|
||||
Widget:
|
||||
size_hint_y: 0.2
|
||||
|
||||
# Action buttons
|
||||
BoxLayout:
|
||||
orientation: 'horizontal'
|
||||
size_hint_y: None
|
||||
height: dp(50)
|
||||
spacing: dp(20)
|
||||
|
||||
Button:
|
||||
text: 'Save & Close'
|
||||
background_color: 0.2, 0.6, 0.2, 1
|
||||
on_press: root.save_and_close()
|
||||
|
||||
Button:
|
||||
text: 'Cancel'
|
||||
background_color: 0.6, 0.2, 0.2, 1
|
||||
on_press: root.dismiss()
|
||||
Reference in New Issue
Block a user