bigger picture, footer

This commit is contained in:
cpu
2025-03-23 20:14:50 +01:00
parent 1cfcd628d4
commit 8a6947f4ea
6 changed files with 277 additions and 28 deletions

154
apps.js
View File

@@ -27,6 +27,14 @@ const imagePreview = document.getElementById('imagePreview');
const playerTimeContainer = document.getElementById('playerTimeContainer');
const remainingTimeContainer = document.getElementById('remainingTimeContainer');
const playerRemainingTime = document.getElementById('playerRemainingTime');
const cameraButton = document.getElementById('cameraButton');
const cameraContainer = document.getElementById('cameraContainer');
const cameraView = document.getElementById('cameraView');
const cameraCanvas = document.getElementById('cameraCanvas');
const cameraCaptureButton = document.getElementById('cameraCaptureButton');
const cameraCancelButton = document.getElementById('cameraCancelButton');
let stream = null;
// Add sound toggle button
const createSoundToggleButton = () => {
@@ -379,7 +387,8 @@ setupButton.addEventListener('click', () => {
playerModal.classList.add('active');
deletePlayerButton.style.display = 'block';
cleanupCameraData();
// Play modal open sound
audioManager.play('modalOpen');
});
@@ -401,6 +410,7 @@ addPlayerButton.addEventListener('click', () => {
playerModal.classList.add('active');
deletePlayerButton.style.display = 'none';
cleanupCameraData();
// Play modal open sound
audioManager.play('modalOpen');
@@ -464,7 +474,78 @@ function parseTimeString(timeString) {
return (minutes * 60) + seconds;
}
// Player form submit
// Camera button click handler
cameraButton.addEventListener('click', async (e) => {
e.preventDefault();
// Check if the browser supports getUserMedia
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
alert('Your browser does not support camera access or it is not available on this device.');
return;
}
try {
// Get permission and access to the camera
stream = await navigator.mediaDevices.getUserMedia({
video: {
facingMode: 'user', // Default to front camera
width: { ideal: 1280 },
height: { ideal: 720 }
}
});
// Show the camera UI
cameraContainer.classList.add('active');
// Attach the stream to the video element
cameraView.srcObject = stream;
} catch (error) {
console.error('Error accessing camera:', error);
alert('Could not access the camera: ' + error.message);
}
});
// Camera capture button click handler
cameraCaptureButton.addEventListener('click', () => {
// Set canvas dimensions to match video
cameraCanvas.width = cameraView.videoWidth;
cameraCanvas.height = cameraView.videoHeight;
// Draw the current video frame to the canvas
const context = cameraCanvas.getContext('2d');
context.drawImage(cameraView, 0, 0, cameraCanvas.width, cameraCanvas.height);
// Convert canvas to data URL
const imageDataUrl = cameraCanvas.toDataURL('image/jpeg');
// Update the image preview with the captured photo
imagePreview.innerHTML = `<img src="${imageDataUrl}" alt="Player">`;
// Stop the camera stream and close the camera UI
stopCameraStream();
cameraContainer.classList.remove('active');
// Since we're capturing directly, we don't need to use the file input
// Instead, store the data URL to use when saving the player
playerImage.dataset.capturedImage = imageDataUrl;
playerImage.value = ''; // Clear the file input
});
// Camera cancel button handler
cameraCancelButton.addEventListener('click', () => {
stopCameraStream();
cameraContainer.classList.remove('active');
});
// Function to stop the camera stream
function stopCameraStream() {
if (stream) {
stream.getTracks().forEach(track => track.stop());
stream = null;
}
}
// Player form submit - FIXED VERSION
playerForm.addEventListener('submit', (e) => {
e.preventDefault();
@@ -484,11 +565,11 @@ playerForm.addEventListener('submit', (e) => {
remainingTimeValue = parseTimeString(remainingTimeString);
}
// Get image if uploaded
const imageFile = document.getElementById('playerImage').files[0];
// Check for captured image from camera
let playerImageData = null;
const capturedImage = playerImage.dataset.capturedImage;
// Function to proceed with saving player
// Define the savePlayer function
const savePlayer = () => {
const isNewPlayer = document.getElementById('modalTitle').textContent === 'Add New Player';
@@ -531,25 +612,33 @@ playerForm.addEventListener('submit', (e) => {
saveData();
playerModal.classList.remove('active');
document.getElementById('playerImage').value = '';
playerImage.dataset.capturedImage = ''; // Clear captured image data
// Also play modal close sound
audioManager.play('modalClose');
};
// Process image if there is one
if (imageFile) {
const reader = new FileReader();
reader.onload = (event) => {
playerImageData = event.target.result;
savePlayer();
};
reader.readAsDataURL(imageFile);
} else {
// Current player's existing image or null
if (document.getElementById('modalTitle').textContent !== 'Add New Player') {
playerImageData = players[currentPlayerIndex].image;
}
// Process image: either from captured image or uploaded file
if (capturedImage) {
playerImageData = capturedImage;
savePlayer();
} else {
// Check for uploaded file
const imageFile = document.getElementById('playerImage').files[0];
if (imageFile) {
const reader = new FileReader();
reader.onload = (event) => {
playerImageData = event.target.result;
savePlayer();
};
reader.readAsDataURL(imageFile);
} else {
// Current player's existing image or null
if (document.getElementById('modalTitle').textContent !== 'Add New Player') {
playerImageData = players[currentPlayerIndex].image;
}
savePlayer();
}
}
});
@@ -558,6 +647,7 @@ cancelButton.addEventListener('click', () => {
audioManager.play('buttonClick');
playerModal.classList.remove('active');
document.getElementById('playerImage').value = '';
cleanupCameraData();
audioManager.play('modalClose');
});
@@ -579,6 +669,7 @@ deletePlayerButton.addEventListener('click', () => {
renderPlayers();
saveData();
playerModal.classList.remove('active');
cleanupCameraData();
// Play player deleted sound
audioManager.play('playerDeleted');
@@ -599,5 +690,32 @@ if ('serviceWorker' in navigator) {
});
}
// Make sure to handle rotation by adding window event listener for orientation changes
window.addEventListener('orientationchange', () => {
// If camera is active, adjust video dimensions
if (cameraContainer.classList.contains('active') && stream) {
// Give a moment for the orientation to complete
setTimeout(() => {
// This may cause the video to briefly reset but will ensure proper dimensions
cameraView.srcObject = null;
cameraView.srcObject = stream;
}, 300);
}
});
// Clean up when the modal is closed
function cleanupCameraData() {
// Clear any captured image data
if (playerImage) {
playerImage.dataset.capturedImage = '';
}
// Make sure camera is stopped
stopCameraStream();
// Hide camera UI if visible
cameraContainer.classList.remove('active');
}
// Initialize the app
loadData();