Added a D-Pad

This commit is contained in:
Ignacio Rivero 2025-03-07 22:54:44 -03:00
parent 20597acd64
commit d7f2f808df
5 changed files with 174 additions and 61 deletions

Binary file not shown.

Binary file not shown.

View File

@ -88,6 +88,34 @@ class IPMPVServer:
def toggle_mute(): def toggle_mute():
return self._handle_toggle_mute() return self._handle_toggle_mute()
@self.app.route("/channel_up")
def channel_up():
return self._handle_channel_up()
@self.app.route("/channel_down")
def channel_down():
return self._handle_channel_down()
@self.app.route('/manifest.json')
def serve_manifest():
return send_from_directory("static", 'manifest.json',
mimetype='application/manifest+json')
@self.app.route('/icon512_rounded.png')
def serve_rounded_icon():
return send_from_directory("static", 'icon512_rounded.png',
mimetype='image/png')
@self.app.route('/icon512_maskable.png')
def serve_maskable_icon():
return send_from_directory("static", 'icon512_maskable.png',
mimetype='image/png')
@self.app.route('/screenshot1.png')
def serve_screenshot_1():
return send_from_directory("static", 'screenshot1.png',
mimetype='image/png')
def _handle_index(self): def _handle_index(self):
"""Handle the index route.""" """Handle the index route."""
from channels import group_channels from channels import group_channels
@ -178,6 +206,28 @@ class IPMPVServer:
thread.start() thread.start()
return "", 204 return "", 204
def _handle_channel_up(self):
"""Handle the channel_up route."""
index = self.player.current_index + 1 if self.player.current_index is not None else 0;
thread = threading.Thread(
target=self.player.play_channel,
args=(index,self.channels),
daemon=True
)
thread.start()
return "", 204
def _handle_channel_down(self):
"""Handle the channel_down route."""
index = self.player.current_index - 1 if self.player.current_index is not None else -1;
thread = threading.Thread(
target=self.player.play_channel,
args=(index,self.channels),
daemon=True
)
thread.start()
return "", 204
def _handle_toggle_deinterlace(self): def _handle_toggle_deinterlace(self):
"""Handle the toggle_deinterlace route.""" """Handle the toggle_deinterlace route."""
state = self.player.toggle_deinterlace() state = self.player.toggle_deinterlace()
@ -219,26 +269,6 @@ class IPMPVServer:
self.resolution = change_resolution(self.resolution) self.resolution = change_resolution(self.resolution)
return jsonify(res=self.resolution) return jsonify(res=self.resolution)
@self.app.route('/manifest.json')
def serve_manifest():
return send_from_directory("static", 'manifest.json',
mimetype='application/manifest+json')
@self.app.route('/icon512_rounded.png')
def serve_rounded_icon():
return send_from_directory("static", 'icon512_rounded.png',
mimetype='image/png')
@self.app.route('/icon512_maskable.png')
def serve_maskable_icon():
return send_from_directory("static", 'icon512_maskable.png',
mimetype='image/png')
@self.app.route('/screenshot1.png')
def serve_screenshot_1():
return send_from_directory("static", 'screenshot1.png',
mimetype='image/png')
def _handle_volume_up(self): def _handle_volume_up(self):
"""Handle the volume_up route.""" """Handle the volume_up route."""
if self.volume_control: if self.volume_control:

View File

@ -37,6 +37,74 @@
line-height: 1.4; line-height: 1.4;
} }
.dpad-container {
position: relative;
width: 240px;
height: 240px;
}
.dpad-container::after {
position: absolute;
top: 80px;
left: 80px;
content: "";
background-color: var(--secondary-bg);
color: white;
width: 80px;
height: 80px;
}
.dpad-button {
position: absolute;
min-width: 80px;
min-height: 80px;
margin: 0;
color: white;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
user-select: none;
transition: background-color 0.2s, transform 0.1s;
}
.dpad-button:hover {
background-color: #555;
}
.dpad-button:active {
background-color: #777;
transform: scale(0.95);
}
#dpad-up {
top: 0;
left: 80px;
border-radius: 10px 10px 0 0;
border-bottom: 0;
}
#dpad-right {
top: 80px;
right: 0;
border-radius: 0 10px 10px 0;
border-left: 0;
}
#dpad-down {
bottom: 0;
left: 80px;
border-radius: 0 0 10px 10px;
border-top: 0;
}
#dpad-left {
top: 80px;
left: 0;
border-radius: 10px 0 0 10px;
border-right: 0;
}
.container { .container {
max-width: 1200px; max-width: 1200px;
margin: 0 auto; margin: 0 auto;
@ -229,6 +297,9 @@
.section { .section {
margin: 20px 0; margin: 20px 0;
padding: 10px; padding: 10px;
display: flex;
flex-direction: column;
align-items: center;
border-radius: var(--border-radius); border-radius: var(--border-radius);
} }
@ -276,7 +347,7 @@
/* Mobile touch improvements */ /* Mobile touch improvements */
@media (max-width: 767px) { @media (max-width: 767px) {
button, button:not(.dpad-button,.leftbtn,.rightbtn,.midbtn),
input { input {
padding: 14px; padding: 14px;
/* Larger touch targets */ /* Larger touch targets */
@ -346,18 +417,9 @@
margin-top: 8px; margin-top: 8px;
} }
#osd-on-btn { .leftbtn, .rightbtn, .midbtn {
margin-top: 8px; width: 90%;
margin-bottom: 8px; padding: 14px;
margin-left: 4px;
min-width: 100px;
}
#osd-off-btn {
margin-top: 8px;
margin-bottom: 8px;
margin-right: 4px;
min-width: 100px;
} }
} }
</style> </style>
@ -368,6 +430,15 @@
<h1>Welcome to IPMPV</h1> <h1>Welcome to IPMPV</h1>
<p>Current Channel: <span id="current-channel">%CURRENT_CHANNEL%</span></p> <p>Current Channel: <span id="current-channel">%CURRENT_CHANNEL%</span></p>
<div class="section">
<div class="dpad-container">
<button id="dpad-up" class="dpad-button" onclick="channelUp()"></button>
<button id="dpad-right" class="dpad-button" onclick="volumeUp()"></button>
<button id="dpad-down" class="dpad-button" onclick="channelDown()"></button>
<button id="dpad-left" class="dpad-button" onclick="volumeDown()"></button>
</div>
</div>
<div class="controls"> <div class="controls">
<button class="control-button" onclick="stopPlayer()">Stop</button> <button class="control-button" onclick="stopPlayer()">Stop</button>
<button id="retroarch-btn" class="%RETROARCH_STATE%" onclick="toggleRetroArch()"> <button id="retroarch-btn" class="%RETROARCH_STATE%" onclick="toggleRetroArch()">
@ -384,9 +455,9 @@
<div class="section"> <div class="section">
<h2>Volume</h2> <h2>Volume</h2>
<div class="osd-toggle"> <div class="osd-toggle">
<button class="leftbtn" id="vol-up-btn" onclick="volumeUp()">+</button> <button class="leftbtn" id="vol-up-btn" onclick="volumeDown()">-</button>
<button class="midbtn %MUTE_STATE%" id="vol-mute-btn" onclick="toggleMute()">mute</button> <button class="midbtn %MUTE_STATE%" id="vol-mute-btn" onclick="toggleMute()">mute</button>
<button class="rightbtn" id="vol-dn-btn" onclick="volumeDown()">-</button> <button class="rightbtn" id="vol-dn-btn" onclick="volumeUp()">+</button>
</div> </div>
</div> </div>
@ -557,6 +628,18 @@
}); });
} }
function channelUp() {
showToast("Loading channel...");
fetch(`/channel_up`)
.then(() => window.location.reload())
}
function channelDown() {
showToast("Loading channel...");
fetch(`/channel_down`)
.then(() => window.location.reload())
}
// Mobile-friendly toast notification // Mobile-friendly toast notification
function showToast(message) { function showToast(message) {
const toast = document.createElement('div'); const toast = document.createElement('div');