diff --git a/apps.js b/apps.js
index a3e1c8e..99987c8 100644
--- a/apps.js
+++ b/apps.js
@@ -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 = ``;
+
+ // 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();
\ No newline at end of file
diff --git a/index.html b/index.html
index f9bbce1..33c2d32 100644
--- a/index.html
+++ b/index.html
@@ -46,7 +46,12 @@