modified: app.py
modified: templates/playerselect.html modified: templates/quiz_buzzer_multiplayer.html new file: templates/team_setup.html
This commit is contained in:
20
app.py
20
app.py
@@ -196,8 +196,13 @@ def quiz(playlist_id):
|
||||
# Wähle das passende Template
|
||||
if buzzer_mode == '1' and local_multiplayer == '1':
|
||||
template_name = "quiz_buzzer_multiplayer.html"
|
||||
# Lade Spieler-Scores
|
||||
player_scores = session.get(f'player_scores_{playlist_id}', [0, 0, 0, 0])
|
||||
# Initialisiere Spieler-Scores basierend auf gespeicherter Team-Anzahl
|
||||
# Default: 6 Teams (Maximum), Frontend lädt nur die konfigurierten
|
||||
player_scores = session.get(f'player_scores_{playlist_id}', [0, 0, 0, 0, 0, 0])
|
||||
# Stelle sicher, dass wir immer 6 Scores haben
|
||||
while len(player_scores) < 6:
|
||||
player_scores.append(0)
|
||||
session[f'player_scores_{playlist_id}'] = player_scores
|
||||
elif buzzer_mode == '1':
|
||||
template_name = "quiz_buzzer.html"
|
||||
player_scores = None
|
||||
@@ -241,6 +246,17 @@ def playerselect(playlist_id):
|
||||
|
||||
return render_template('playerselect.html', playlist_id=playlist_id, game_mode=game_mode, buzzer=buzzer, translations=get_translations(), user=user)
|
||||
|
||||
@app.route('/team_setup/<playlist_id>')
|
||||
def team_setup(playlist_id):
|
||||
"""Configure team names and count for multiplayer buzzer mode."""
|
||||
game_mode = request.args.get('mode', 'title')
|
||||
user = session.get('user')
|
||||
return render_template('team_setup.html',
|
||||
playlist_id=playlist_id,
|
||||
game_mode=game_mode,
|
||||
translations=get_translations(),
|
||||
user=user)
|
||||
|
||||
@app.route('/buzzer_settings/<playlist_id>')
|
||||
def buzzer_settings(playlist_id):
|
||||
"""Configure buzzer mode settings before starting."""
|
||||
|
||||
@@ -66,11 +66,10 @@
|
||||
<button class="player-btn" type="submit">{{ translations['singleplayer'] }}</button>
|
||||
<div class="player-desc">{{ translations['singleplayer_desc'] if translations['singleplayer_desc'] else 'Play alone and test your knowledge.' }}</div>
|
||||
</form>
|
||||
<form method="get" action="{{ url_for('buzzer_settings', playlist_id=playlist_id) }}">
|
||||
<form method="get" action="{{ url_for('team_setup', playlist_id=playlist_id) }}">
|
||||
<input type="hidden" name="mode" value="{{ game_mode }}">
|
||||
<input type="hidden" name="local_multiplayer" value="1">
|
||||
<button class="player-btn" type="submit">{{ translations['local_multiplayer'] }}</button>
|
||||
<div class="player-desc">Spiele mit bis zu 4 Personen an einem Gerät.</div>
|
||||
<div class="player-desc">Spiele mit 2-6 Teams an einem Gerät.</div>
|
||||
</form>
|
||||
{% else %}
|
||||
<form method="get" action="{{ url_for('quiz', playlist_id=playlist_id) }}">
|
||||
|
||||
@@ -244,13 +244,16 @@
|
||||
let gameStarted = false;
|
||||
let currentBuzzer = null;
|
||||
|
||||
// Spieler-Daten
|
||||
let players = [
|
||||
{ id: 1, name: 'Spieler 1', score: {{ player_scores[0] if player_scores else 0 }} },
|
||||
{ id: 2, name: 'Spieler 2', score: {{ player_scores[1] if player_scores else 0 }} },
|
||||
{ id: 3, name: 'Spieler 3', score: {{ player_scores[2] if player_scores else 0 }} },
|
||||
{ id: 4, name: 'Spieler 4', score: {{ player_scores[3] if player_scores else 0 }} }
|
||||
];
|
||||
// Lade Team-Daten aus localStorage
|
||||
let teamCount = parseInt(localStorage.getItem('team_count')) || 4;
|
||||
let players = [];
|
||||
|
||||
for (let i = 1; i <= teamCount; i++) {
|
||||
const teamName = localStorage.getItem(`team_${i}_name`) || `Team ${i}`;
|
||||
const scoreIndex = i - 1;
|
||||
const score = {{ player_scores|tojson }}[scoreIndex] || 0;
|
||||
players.push({ id: i, name: teamName, score: score });
|
||||
}
|
||||
|
||||
window.onSpotifyWebPlaybackSDKReady = () => {
|
||||
const token = '{{ access_token }}';
|
||||
@@ -321,10 +324,10 @@
|
||||
.then(() => {
|
||||
console.log('Play command sent');
|
||||
document.getElementById('startButton').style.display = 'none';
|
||||
// Aktiviere Buzzer
|
||||
for (let i = 1; i <= 4; i++) {
|
||||
document.getElementById(`buzzer${i}`).classList.remove('disabled');
|
||||
}
|
||||
// Aktiviere alle Buzzer
|
||||
players.forEach(player => {
|
||||
document.getElementById(`buzzer${player.id}`).classList.remove('disabled');
|
||||
});
|
||||
})
|
||||
.catch(error => console.error('Error starting playback:', error));
|
||||
}
|
||||
@@ -390,9 +393,9 @@
|
||||
document.getElementById('currentPlayer').textContent = `${players[playerId - 1].name} hat gebuzzert!`;
|
||||
|
||||
// Deaktiviere alle Buzzer
|
||||
for (let i = 1; i <= 4; i++) {
|
||||
document.getElementById(`buzzer${i}`).classList.add('disabled');
|
||||
}
|
||||
players.forEach(player => {
|
||||
document.getElementById(`buzzer${player.id}`).classList.add('disabled');
|
||||
});
|
||||
|
||||
document.getElementById('answerSection').classList.add('active');
|
||||
window.earnedPoints = calculatePoints(elapsed);
|
||||
@@ -533,30 +536,54 @@
|
||||
gracePeriod = parseInt(localStorage.getItem('buzzer_grace_period')) || 5;
|
||||
decayRate = parseInt(localStorage.getItem('buzzer_decay_rate')) || 50;
|
||||
document.getElementById('pointsDisplay').textContent = maxPoints + ' Punkte';
|
||||
|
||||
// Dynamisches Scoreboard erstellen
|
||||
createScoreboard();
|
||||
// Dynamische Buzzer-Buttons erstellen
|
||||
createBuzzerButtons();
|
||||
};
|
||||
|
||||
function createScoreboard() {
|
||||
const scoreboard = document.getElementById('scoreboard');
|
||||
scoreboard.innerHTML = '';
|
||||
|
||||
players.forEach(player => {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'player-card';
|
||||
card.id = `player${player.id}`;
|
||||
card.innerHTML = `
|
||||
<div class="player-name">${player.name}</div>
|
||||
<div class="player-score">${player.score}</div>
|
||||
`;
|
||||
scoreboard.appendChild(card);
|
||||
});
|
||||
}
|
||||
|
||||
function createBuzzerButtons() {
|
||||
const grid = document.getElementById('buzzerGrid');
|
||||
grid.innerHTML = `
|
||||
<button class="player-buzzer start" id="startButton" onclick="startGame()">
|
||||
▶️<br>START
|
||||
</button>
|
||||
`;
|
||||
|
||||
players.forEach(player => {
|
||||
const button = document.createElement('button');
|
||||
button.className = 'player-buzzer disabled';
|
||||
button.id = `buzzer${player.id}`;
|
||||
button.onclick = () => buzz(player.id);
|
||||
button.innerHTML = `🔴<br>${player.name}`;
|
||||
grid.appendChild(button);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<div class="quiz-container">
|
||||
<!-- Scoreboard -->
|
||||
<div class="scoreboard">
|
||||
<div class="player-card" id="player1">
|
||||
<div class="player-name">Spieler 1</div>
|
||||
<div class="player-score">0</div>
|
||||
</div>
|
||||
<div class="player-card" id="player2">
|
||||
<div class="player-name">Spieler 2</div>
|
||||
<div class="player-score">0</div>
|
||||
</div>
|
||||
<div class="player-card" id="player3">
|
||||
<div class="player-name">Spieler 3</div>
|
||||
<div class="player-score">0</div>
|
||||
</div>
|
||||
<div class="player-card" id="player4">
|
||||
<div class="player-name">Spieler 4</div>
|
||||
<div class="player-score">0</div>
|
||||
</div>
|
||||
<div class="scoreboard" id="scoreboard">
|
||||
<!-- Dynamisch generiert via JavaScript -->
|
||||
</div>
|
||||
|
||||
<input type="hidden" id="device_id" value="">
|
||||
@@ -570,22 +597,8 @@
|
||||
<div class="current-player" id="currentPlayer">Drücke START um zu beginnen</div>
|
||||
|
||||
<!-- Buzzer Buttons -->
|
||||
<div class="buzzer-grid">
|
||||
<button class="player-buzzer start" id="startButton" onclick="startGame()">
|
||||
▶️<br>START
|
||||
</button>
|
||||
<button class="player-buzzer disabled" id="buzzer1" onclick="buzz(1)">
|
||||
🔴<br>Spieler 1
|
||||
</button>
|
||||
<button class="player-buzzer disabled" id="buzzer2" onclick="buzz(2)">
|
||||
🔴<br>Spieler 2
|
||||
</button>
|
||||
<button class="player-buzzer disabled" id="buzzer3" onclick="buzz(3)">
|
||||
🔴<br>Spieler 3
|
||||
</button>
|
||||
<button class="player-buzzer disabled" id="buzzer4" onclick="buzz(4)">
|
||||
🔴<br>Spieler 4
|
||||
</button>
|
||||
<div class="buzzer-grid" id="buzzerGrid">
|
||||
<!-- Dynamisch generiert via JavaScript -->
|
||||
</div>
|
||||
|
||||
<!-- Answer Section -->
|
||||
|
||||
227
templates/team_setup.html
Normal file
227
templates/team_setup.html
Normal file
@@ -0,0 +1,227 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ translations['quiz_title'] }} – Team Setup</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #0a0e27 0%, #1a1f3a 50%, #0f1419 100%);
|
||||
color: #e0e0e0;
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.setup-container {
|
||||
max-width: 700px;
|
||||
width: 100%;
|
||||
background: rgba(25, 30, 45, 0.95);
|
||||
border-radius: 20px;
|
||||
padding: 40px;
|
||||
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.5);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
h2 {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
color: #1DB954;
|
||||
font-size: 2em;
|
||||
}
|
||||
.team-count-section {
|
||||
margin-bottom: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
.team-count-label {
|
||||
font-size: 1.3em;
|
||||
margin-bottom: 15px;
|
||||
color: #e0e0e0;
|
||||
font-weight: 600;
|
||||
}
|
||||
.team-count-display {
|
||||
font-size: 3em;
|
||||
font-weight: bold;
|
||||
color: #1DB954;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.team-count-slider {
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
border-radius: 5px;
|
||||
background: rgba(29, 185, 84, 0.2);
|
||||
outline: none;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
.team-count-slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
border-radius: 50%;
|
||||
background: #1DB954;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 10px rgba(29, 185, 84, 0.5);
|
||||
}
|
||||
.team-count-slider::-moz-range-thumb {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
border-radius: 50%;
|
||||
background: #1DB954;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 0 10px rgba(29, 185, 84, 0.5);
|
||||
border: none;
|
||||
}
|
||||
.teams-list {
|
||||
margin: 30px 0;
|
||||
}
|
||||
.team-input-group {
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
.team-number {
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
color: #1DB954;
|
||||
min-width: 100px;
|
||||
}
|
||||
.team-name-input {
|
||||
flex: 1;
|
||||
padding: 12px 20px;
|
||||
border-radius: 12px;
|
||||
border: 2px solid rgba(29, 185, 84, 0.3);
|
||||
background: rgba(15, 20, 25, 0.8);
|
||||
color: #e0e0e0;
|
||||
font-size: 1.1em;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.team-name-input:focus {
|
||||
outline: none;
|
||||
border-color: #1DB954;
|
||||
box-shadow: 0 0 10px rgba(29, 185, 84, 0.3);
|
||||
}
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 15px 30px;
|
||||
margin: 10px 5px;
|
||||
border-radius: 25px;
|
||||
border: none;
|
||||
font-size: 1.1em;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
}
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #1DB954 0%, #1ed760 100%);
|
||||
box-shadow: 0 4px 15px rgba(29, 185, 84, 0.3);
|
||||
}
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(29, 185, 84, 0.5);
|
||||
}
|
||||
.btn-secondary {
|
||||
background: linear-gradient(135deg, #535353 0%, #666 100%);
|
||||
}
|
||||
.btn-secondary:hover {
|
||||
transform: translateY(-2px);
|
||||
background: linear-gradient(135deg, #666 0%, #777 100%);
|
||||
}
|
||||
.button-group {
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
let teamCount = 4;
|
||||
|
||||
function updateTeamCount() {
|
||||
teamCount = parseInt(document.getElementById('teamCountSlider').value);
|
||||
document.getElementById('teamCountDisplay').textContent = teamCount;
|
||||
updateTeamInputs();
|
||||
}
|
||||
|
||||
function updateTeamInputs() {
|
||||
const container = document.getElementById('teamInputs');
|
||||
container.innerHTML = '';
|
||||
|
||||
for (let i = 1; i <= teamCount; i++) {
|
||||
const savedName = localStorage.getItem(`team_${i}_name`) || `Team ${i}`;
|
||||
|
||||
const group = document.createElement('div');
|
||||
group.className = 'team-input-group';
|
||||
group.innerHTML = `
|
||||
<div class="team-number">Team ${i}:</div>
|
||||
<input type="text"
|
||||
class="team-name-input"
|
||||
id="team${i}Name"
|
||||
value="${savedName}"
|
||||
placeholder="Team ${i} Name"
|
||||
maxlength="20">
|
||||
`;
|
||||
container.appendChild(group);
|
||||
}
|
||||
}
|
||||
|
||||
function saveTeams() {
|
||||
// Speichere Anzahl
|
||||
localStorage.setItem('team_count', teamCount);
|
||||
|
||||
// Speichere Namen
|
||||
for (let i = 1; i <= teamCount; i++) {
|
||||
const name = document.getElementById(`team${i}Name`).value || `Team ${i}`;
|
||||
localStorage.setItem(`team_${i}_name`, name);
|
||||
}
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
// Lade gespeicherte Anzahl
|
||||
const savedCount = localStorage.getItem('team_count') || '4';
|
||||
document.getElementById('teamCountSlider').value = savedCount;
|
||||
updateTeamCount();
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="setup-container">
|
||||
<h2>👥 Team Setup</h2>
|
||||
|
||||
<div class="team-count-section">
|
||||
<div class="team-count-label">Anzahl der Teams</div>
|
||||
<div class="team-count-display" id="teamCountDisplay">4</div>
|
||||
<input type="range"
|
||||
class="team-count-slider"
|
||||
id="teamCountSlider"
|
||||
min="2"
|
||||
max="6"
|
||||
value="4"
|
||||
oninput="updateTeamCount()">
|
||||
</div>
|
||||
|
||||
<div class="teams-list">
|
||||
<div id="teamInputs"></div>
|
||||
</div>
|
||||
|
||||
<div class="button-group">
|
||||
<a href="{{ url_for('buzzer_settings', playlist_id=playlist_id) }}?mode={{ game_mode }}&local_multiplayer=1"
|
||||
class="btn btn-primary"
|
||||
onclick="saveTeams()">
|
||||
✅ Weiter zu Einstellungen
|
||||
</a>
|
||||
<a href="{{ url_for('playerselect', playlist_id=playlist_id) }}?mode={{ game_mode }}&buzzer=1"
|
||||
class="btn btn-secondary">
|
||||
⬅️ Zurück
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user