diff --git a/Interface/.DS_Store b/Interface/.DS_Store index 7e5af11257301b1b3d1c2eca098587a8249e3ddf..57141212022ff4cd70db7530b16f576de2515a18 100644 Binary files a/Interface/.DS_Store and b/Interface/.DS_Store differ diff --git a/Interface/classification_video.py b/Interface/classification_video.py new file mode 100644 index 0000000000000000000000000000000000000000..1f457f855117325b8c4babf3f9bab0d7e36963bf --- /dev/null +++ b/Interface/classification_video.py @@ -0,0 +1,287 @@ +import cv2 +import os +import shutil +import tkinter as tk +from tkinter import ttk, simpledialog, messagebox, filedialog +import threading +import time + +class VideoPlayer: + def __init__(self): + self.is_playing = False + self.current_video = None + self.stop_event = threading.Event() + self.play_thread = None + self.speed = 1.0 + + def play_video(self, video_path, speed=1.0): + """Démarre la lecture d'une vidéo en boucle dans un thread séparé""" + self.stop_event.clear() + self.is_playing = True + self.current_video = video_path + self.speed = speed + + # Créer un nouveau thread pour la lecture + self.play_thread = threading.Thread(target=self._play_video_loop) + self.play_thread.daemon = True + self.play_thread.start() + + def _play_video_loop(self): + """Joue la vidéo en boucle jusqu'à ce que stop_event soit déclenché""" + while not self.stop_event.is_set(): + cap = cv2.VideoCapture(self.current_video) + if not cap.isOpened(): + print(f"Erreur : Impossible d'ouvrir {self.current_video}") + break + + fps = cap.get(cv2.CAP_PROP_FPS) + delay = int(1000 / (fps * self.speed)) + + while cap.isOpened() and not self.stop_event.is_set(): + ret, frame = cap.read() + if not ret: + break # Fin de la vidéo, on recommence + + cv2.imshow("Lecture Vidéo", frame) + if cv2.waitKey(delay) & 0xFF == ord('q'): + self.stop() + break + + cap.release() + + # Si on a atteint la fin mais que stop_event n'est pas déclenché, + # on recommence la lecture depuis le début + if not self.stop_event.is_set(): + continue + else: + break + + def stop(self): + """Arrête la lecture de la vidéo""" + self.stop_event.set() + if self.play_thread: + self.play_thread.join(timeout=1.0) + self.is_playing = False + cv2.destroyAllWindows() + +def get_selection(title, options, root=None): + """Fenêtre avec un menu déroulant pour faire un choix""" + # Vérifier si une instance root a été passée, sinon en créer une nouvelle + own_root = False + if root is None: + root = tk.Tk() + root.withdraw() + own_root = True + + selection_window = tk.Toplevel(root) + selection_window.title(title) + selection_window.geometry("300x150") + selection_window.lift() # Amener la fenêtre au premier plan + selection_window.focus_force() # Forcer le focus + + tk.Label(selection_window, text=title).pack(pady=5) + selected_value = tk.StringVar() + dropdown = ttk.Combobox(selection_window, textvariable=selected_value, values=options, state='readonly') + dropdown.pack(pady=5) + dropdown.current(0) + + def validate(): + selection_window.destroy() + + tk.Button(selection_window, text="Valider", command=validate).pack(pady=10) + selection_window.wait_window() + + # Si nous avons créé notre propre root, il faut le détruire + if own_root: + root.destroy() + + return selected_value.get() + +def classifier_video(video_path, liste_joueuses, cpt, video_player, root): + """Interface utilisateur pour classifier ou supprimer une vidéo avec des menus déroulants""" + if messagebox.askyesno("Suppression", "Voulez-vous supprimer cette vidéo ?"): + video_player.stop() + os.remove(video_path) + print(f"Vidéo supprimée : {video_path}") + return None + + joueuse = get_selection("Sélectionnez une joueuse", liste_joueuses, root) + if not joueuse: + return None + + action_types = ["Réception", "Passe", "Défense", "Autre"] + action = get_selection("Sélectionnez une action", action_types, root) + if not action: + return None + + passe_types = { + "Bonne passe (verte)": "Bonne passe", + "Bonne hauteur, mauvaise zone (bleue)": "Bonne hauteur, mauvaise zone", + "Bonne zone, mauvaise hauteur (blanche)": "Bonne zone, mauvaise hauteur", + "Mauvaise passe (rouge)": "Mauvaise passe" + } + passe_result = None + if action == "Passe": + passe_result = get_selection("Qualité de Passe", list(passe_types.keys()), root) + passe_result = passe_types.get(passe_result) + + new_name = f"{joueuse}_{action}" + if passe_result: + new_name += f"_{passe_result}" + + # On ne change pas l'extension pour conserver le format d'origine + extension = os.path.splitext(video_path)[-1] + new_name += f"_{cpt}{extension}" + + # Arrêter la lecture de la vidéo une fois la classification terminée + video_player.stop() + + return joueuse, action, passe_result, new_name + +def concatener_videos_cv2(video_paths, destination_path): + """Concatène les vidéos en utilisant OpenCV""" + if not video_paths: + return False + + if len(video_paths) == 1: + # S'il n'y a qu'une seule vidéo, la copier simplement + shutil.copy(video_paths[0], destination_path) + return True + + # Récupérer les propriétés de la première vidéo + cap = cv2.VideoCapture(video_paths[0]) + frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + fps = int(cap.get(cv2.CAP_PROP_FPS)) + cap.release() + + # Créer l'objet VideoWriter pour la vidéo de sortie + fourcc = cv2.VideoWriter_fourcc(*'mp4v') # Codec pour mp4 + out = cv2.VideoWriter(destination_path, fourcc, fps, (frame_width, frame_height)) + + # Parcourir chaque vidéo et ajouter ses frames à la vidéo de sortie + for video_path in video_paths: + cap = cv2.VideoCapture(video_path) + while True: + ret, frame = cap.read() + if not ret: + break + out.write(frame) + cap.release() + + # Libérer l'objet VideoWriter + out.release() + return True + +def organiser_videos(video_list, liste_joueuses): + """Affiche et trie une liste de vidéos en fonction des critères choisis""" + # Créer une seule instance de Tk pour toute l'application + root = tk.Tk() + root.withdraw() # Cacher la fenêtre principale + + cpt = 0 + speed_choice = get_selection("Vitesse de Lecture", ["1", "1.5", "2"], root) + speed = float(speed_choice) if speed_choice else 1.0 + + # Créer un lecteur vidéo + video_player = VideoPlayer() + + # Dictionnaire pour stocker les vidéos par catégorie + videos_par_categorie = {} + + # Liste pour stocker les fichiers à supprimer à la fin + files_to_delete = [] + + for video in video_list: + if os.path.exists(video): + print(f"Affichage de la vidéo : {video}") + + # Lancer la lecture de la vidéo en boucle + video_player.play_video(video, speed) + + # Attendre un peu pour que la vidéo commence à s'afficher + time.sleep(0.5) + + # Classifier la vidéo pendant qu'elle est en lecture + classification = classifier_video(video, liste_joueuses, cpt, video_player, root) + cpt += 1 + + if classification: + joueuse, action, passe_result, new_name = classification + + # Créer une clé unique pour cette catégorie + categorie_key = f"{joueuse}/{action}" + if action == "Passe" and passe_result: + categorie_key += f"/{passe_result}" + + # Ajouter la vidéo à sa catégorie + if categorie_key not in videos_par_categorie: + videos_par_categorie[categorie_key] = [] + + videos_par_categorie[categorie_key].append((video, new_name)) + + # Ajouter le fichier à la liste des fichiers à supprimer + files_to_delete.append(video) + + # S'assurer que la lecture est arrêtée + video_player.stop() + if videos_par_categorie != {}: + # Demander le dossier de destination + base_dir = filedialog.askdirectory(title="Sélectionnez le dossier de destination", parent=root) + if not base_dir: + root.destroy() + return + + + # Traiter chaque catégorie + for categorie, videos in videos_par_categorie.items(): + # Créer le dossier de destination + dest_dir = os.path.join(base_dir, categorie) + os.makedirs(dest_dir, exist_ok=True) + + # Créer les chemins temporaires pour les vidéos + temp_video_paths = [] + for video_path, new_name in videos: + temp_path = os.path.join(dest_dir, new_name) + shutil.copy(video_path, temp_path) + temp_video_paths.append(temp_path) + + # Créer le nom du fichier final concaténé + categorie_name = categorie.replace('/', '_') + output_file = os.path.join(dest_dir, f"{categorie_name}_complet.mp4") + + + # Concaténer les vidéos + if concatener_videos_cv2(temp_video_paths, output_file): + print(f"Vidéos concaténées dans {output_file}") + + # Supprimer les fichiers temporaires + for temp_path in temp_video_paths: + if os.path.exists(temp_path): + os.remove(temp_path) + + # Supprimer les fichiers d'origine + if messagebox.askyesno("Suppression des originaux", "Voulez-vous supprimer les vidéos originales ?", parent=root): + for file_path in files_to_delete: + if os.path.exists(file_path): + try: + os.remove(file_path) + print(f"Fichier original supprimé : {file_path}") + except Exception as e: + print(f"Erreur lors de la suppression de {file_path}: {e}") + + # Détruire la fenêtre principale à la fin + root.destroy() + +# Programme principal +liste_joueuses = ["lilou", "sadio", "ester"] + +# Initialisation de Tk pour le sélecteur de dossier initial +root_initial = tk.Tk() +root_initial.withdraw() +video_folder = filedialog.askdirectory(title="Sélectionnez le dossier contenant les vidéos", parent=root_initial) +root_initial.destroy() + +if video_folder: + videos = [os.path.join(video_folder, f) for f in os.listdir(video_folder) if f.endswith(('.mp4', '.avi', '.mov'))] + organiser_videos(videos, liste_joueuses) diff --git a/Interface/css/.DS_Store b/Interface/css/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b0ede4f008118971907572fca11039841fac5b7d Binary files /dev/null and b/Interface/css/.DS_Store differ diff --git a/Interface/css/edit-styles-moche.css b/Interface/css/edit-styles-moche.css new file mode 100644 index 0000000000000000000000000000000000000000..9a46243775c155432d9bd74afab52bd08c52253d --- /dev/null +++ b/Interface/css/edit-styles-moche.css @@ -0,0 +1,60 @@ +body { + font-family: Arial, sans-serif; + background-color: #013069; + color: white; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; +} +.container { + background-color: #014886; + padding: 20px; + border-radius: 10px; + width: 400px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); +} +.header { + display: flex; + align-items: center; + gap: 15px; + margin-bottom: 15px; +} +.profile-pic { + width: 80px; + height: 80px; + border-radius: 50%; + object-fit: cover; + border: 2px solid #F9BE01; +} +.fields { + display: flex; + flex-direction: column; + margin-top: 15px; +} +input, textarea { + margin-bottom: 15px; + padding: 8px; + border: none; + border-radius: 5px; +} +.date-picker { + margin-top: 10px; +} +.buttons { + display: flex; + justify-content: flex-end; + gap: 10px; + margin-top: 15px; +} +button { + background-color: #F9BE01; + color: black; + border: none; + padding: 10px; + border-radius: 20px; + cursor: pointer; +} +button:hover { + background-color: #FBCE01; +} \ No newline at end of file diff --git a/Interface/css/edit-styles.css b/Interface/css/edit-styles.css new file mode 100644 index 0000000000000000000000000000000000000000..c5ab96a85c056bf087417be58a77b48e21f66beb --- /dev/null +++ b/Interface/css/edit-styles.css @@ -0,0 +1,298 @@ +/* Variables de couleurs pour la palette */ +:root { + --dark-blue: #013069; + --medium-blue: #014886; + --light-blue: #015A9B; + --dark-yellow: #F9BE01; + --light-yellow: #FBCE01; + --background: #f8f9fa; + --text-color: #333; + --card-background: white; + } + + /* Style général */ + body { + background-color: var(--background); + color: var(--text-color); + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + padding: 0; + margin: 0; + } + + #layoutSidenav_content { + padding: 30px; + } + + .container-fluid { + margin: 30px; + max-width: 1200px; + } + + h1 { + color: var(--dark-blue); + margin-bottom: 20px; + border-bottom: 3px solid var(--dark-yellow); + padding-bottom: 10px; + } + + /* Carte principale */ + #layoutSidenav_content main { + background-color: var(--background); + padding: 20px; + } + + .container-fluid { + background-color: var(--card-background); + border-radius: 10px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + padding: 30px; + border-left: 5px solid var(--light-blue); + box-sizing: border-box; /* Assurons-nous que padding est inclus dans la largeur */ + overflow: hidden; /* Évite tout débordement */ + } + + /* En-tête du profil de joueuse */ + .player-header { + display: flex; + align-items: center; /* Aligne verticalement au centre */ + margin-bottom: 30px; + padding-bottom: 20px; + border-bottom: 2px solid var(--light-yellow); + flex-wrap: wrap; /* Permet le passage à la ligne sur petits écrans */ + } + + /* Section photo - Modifiée pour placer le bouton en dessous */ + .photo-section { + margin-right: 20px; + display: flex; + flex-direction: column; + align-items: center; + min-width: 130px; + margin-bottom: 15px; /* Espace en dessous pour le mode responsive */ + } + + .player-photo { + width: 120px; + height: 120px; + border-radius: 50%; + object-fit: cover; + border: 3px solid var(--light-blue); + box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1); + } + + #changePhoto { + margin-top: 10px; + background-color: var(--light-blue); + color: white; + border: none; + border-radius: 20px; + padding: 8px 16px; + cursor: pointer; + transition: background-color 0.3s; + font-size: 0.9em; + width: 100%; + text-align: center; + } + + #changePhoto:hover { + background-color: var(--medium-blue); + } + + /* Section nom - Alignement vertical et largeur contrôlée */ + .name-section { + flex: 1; + max-width: calc(100% - 170px); /* Évite de dépasser sur petits écrans */ + padding-right: 10px; + box-sizing: border-box; + display: flex; + justify-content: center; /* Centre le champ de texte horizontalement */ + } + + #editPlayerName { + width: 100%; + max-width: 300px; + height: 40px; + padding: 10px; + font-size: 16px; + border: 1px solid #ddd; + border-radius: 5px; + resize: none; + background-color: #f9f9f9; + } + + /* Détails de la joueuse */ + .player-details { + display: flex; + flex-direction: column; + align-items: flex-start; + margin-bottom: 20px; + background-color: rgba(1, 90, 155, 0.05); + padding: 20px; + border-radius: 8px; + } + + .detail-item { + margin-bottom: 15px; + width: 100%; + display: flex; + flex-direction: row; + align-items: center; + flex-wrap: wrap; + } + + .detail-item b { + min-width: 150px; + color: var(--dark-blue); + margin-right: 10px; + } + + .detail-item select, + .detail-item input { + padding: 8px; + border: 1px solid #ddd; + border-radius: 5px; + width: 150px; + background-color: white; + margin: 0 10px 0 0; + } + + .unit { + color: #666; + display: inline-block; + white-space: nowrap; + } + + /* Section commentaires - Plus de marge à droite */ + .comment-section { + margin-bottom: 30px; + width: 100%; + box-sizing: border-box; + } + + .comment-section b { + display: block; + margin-bottom: 10px; + color: var(--dark-blue); + } + + #editPlayerComments { + width: calc(95%); + min-height: 100px; + padding: 15px; + border: 1px solid #ddd; + border-radius: 5px; + resize: vertical; + margin-right: 40px; + background-color: #f9f9f9; + } + + /* Boutons d'édition */ + .edit-buttons { + display: flex; + justify-content: flex-end; + margin-top: 20px; + gap: 15px; + border-top: 2px solid var(--light-yellow); + padding-top: 20px; + } + + #saveChanges, + #cancelChanges { + padding: 10px 25px; + border: none; + border-radius: 20px; + cursor: pointer; + font-weight: bold; + transition: all 0.3s; + } + + #saveChanges { + background-color: var(--dark-yellow); + color: var(--dark-blue); + box-shadow: 0 2px 4px rgba(249, 190, 1, 0.3); + } + + #saveChanges:hover { + background-color: var(--light-yellow); + transform: translateY(-2px); + } + + #cancelChanges { + background-color: #f0f0f0; + color: var(--dark-blue); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + } + + #cancelChanges:hover { + background-color: #e0e0e0; + transform: translateY(-2px); + } + + /* Styles responsifs améliorés */ + @media (max-width: 992px) { + .container-fluid { + margin: 20px; + padding: 20px; + } + + .detail-item { + flex-wrap: wrap; + } + + .detail-item b { + width: 100%; + margin-bottom: 5px; + } + + .detail-item input, + .detail-item select { + margin-left: 0; + flex-grow: 1; + max-width: calc(100% - 50px); + } + } + + @media (max-width: 768px) { + #layoutSidenav_content { + padding: 15px; + } + + .container-fluid { + margin: 10px; + padding: 15px; + width: auto; + } + + .player-header { + flex-direction: column; + align-items: center; /* Centre les éléments horizontalement */ + } + + .photo-section { + margin-right: 0; + margin-bottom: 20px; + width: 100%; + align-items: center; /* Centre la photo et le bouton */ + } + + .name-section { + width: 100%; + max-width: 100%; + padding-right: 0; + justify-content: center; /* Centre le champ de nom */ + } + + #editPlayerName { + max-width: 100%; + width: calc(100% - 20px); + } + + #editPlayerComments { + width: calc(95%); + margin-right: 20px; + } + + .edit-buttons { + justify-content: center; + } + } \ No newline at end of file diff --git a/Interface/css/input-styles.css b/Interface/css/input-styles.css new file mode 100644 index 0000000000000000000000000000000000000000..9434341a8f77f83a8d631c08e6181c2b1e9fc694 --- /dev/null +++ b/Interface/css/input-styles.css @@ -0,0 +1,100 @@ +:root { + --dark-blue: #253850; + --medium-blue:#2d4861; + --light-blue: #4A7CA6; + --dark-yellow: #F9BE01; + --light-yellow: #FBCE01; + --background: #f8f9fa; + --text-color: #333; + --card-background: white; + } + + /* Style général */ + body { + background-color: var(--background); + color: var(--text-color); + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + padding: 0; + margin: 0; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + } + + .container { + background-color: var(--card-background); + border-radius: 10px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + padding: 30px; + border-left: 5px solid var(--light-blue); + width: 90%; + max-width: 400px; + position: relative; + } + + h3 { + color: var(--dark-blue); + margin-bottom: 20px; + border-bottom: 3px solid var(--dark-yellow); + padding-bottom: 10px; + } + + #playerName { + width: 80%; + padding: 10px; + margin-bottom: 20px; + border: 1px solid #ddd; + border-radius: 5px; + font-size: 16px; + } + + #submitButton { + background-color: var(--dark-yellow); + color: var(--dark-blue); + border: none; + border-radius: 20px; + padding: 10px 25px; + cursor: pointer; + font-weight: bold; + transition: all 0.3s; + box-shadow: 0 2px 4px rgba(249, 190, 1, 0.3); + } + + #submitButton:hover { + background-color: var(--light-yellow); + transform: translateY(-2px); + } + + /* Bouton retour (croix) */ + #backButton { + position: absolute; + top: 10px; + right: 10px; + background-color: var(--medium-blue); + color: white; + border: none; + border-radius: 50%; + width: 30px; + height: 30px; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + font-size: 16px; + transition: background-color 0.3s; + } + + #backButton:hover { + background-color: var(--dark-blue); + } + + /* Styles responsifs */ + @media (max-width: 768px) { + .container { + width: 85%; + padding: 20px; + } + } + + diff --git a/Interface/css/styles.css b/Interface/css/styles.css index 9c76eb4233c328da928e103c44a5cdb21ce29f06..2865a920c36d75562896b470ee3469c1eae12572 100644 --- a/Interface/css/styles.css +++ b/Interface/css/styles.css @@ -11311,3 +11311,77 @@ table#datatablesSimple td:nth-child(2) { .bar-section.blue { background-color: blue; } + + +/* ---------- PLAYER CARD (tables.html) ---------- */ +.player-card { + display: flex; + flex-direction: column; + align-items: flex-start; + padding: 20px; + border: 1px solid #ccc; + border-radius: 10px; + margin-bottom: 20px; +} + +.player-header { + display: flex; + align-items: center; + margin-bottom: 20px; +} + +.player-photo { + width: 100px; + height: 100px; + border-radius: 50%; + margin-right: 20px; + object-fit: cover; +} + +.player-header h2 { + margin: 0; + font-size: 24px; +} + +.edit-icon { + width: 20px; + height: 20px; + margin-left: 10px; + cursor: pointer; +} + +/* ---------- PLAYER DETAILS (tables.html) ---------- */ +.player-details { + display: flex; + flex-wrap: wrap; /* Permet aux éléments de rester en ligne mais passer à la ligne si nécessaire */ + justify-content: space-between; + align-items: center; + width: 100%; + gap: 10px; +} + +.detail-item { + display: flex; + align-items: center; + gap: 5px; + flex-grow: 1; /* Permet de répartir les éléments sur la ligne */ + min-width: 150px; /* Empêche les éléments de devenir trop petits */ + white-space: nowrap; /* Évite que le texte se coupe en plusieurs lignes */ +} + +/* ---------- COMMENT SECTION ---------- */ +.comment-section { + width: 100%; +} + +.comment-section label { + font-weight: bold; +} + +.comment-section p { + margin: 10px 0 0; + padding: 10px; + border: 1px solid #ccc; + border-radius: 5px; + background-color: #f9f9f9; +} diff --git a/Interface/data/.DS_Store b/Interface/data/.DS_Store index 9ef325512c9a4cb8946c35f0ed445270b614bd8e..d3b15e69d025b811e0f517e0d3caf9009467e1bf 100644 Binary files a/Interface/data/.DS_Store and b/Interface/data/.DS_Store differ diff --git a/Interface/data/data1.json b/Interface/data/data1.json new file mode 100644 index 0000000000000000000000000000000000000000..771780892917cc1449f87cd90501a6cc56732b5c --- /dev/null +++ b/Interface/data/data1.json @@ -0,0 +1,314 @@ +[ + { + "date": "01/11/2024", + "heure": "20:00", + "performance": [ + { + "color": "green", + "percentage": 28 + }, + { + "color": "blue", + "percentage": 18 + }, + { + "color": "black", + "percentage": 12 + }, + { + "color": "red", + "percentage": 42 + } + ], + "video": null, + "video_duration": "01:10" + }, + { + "date": "02/11/2024", + "heure": "14:00", + "performance": [ + { + "color": "green", + "percentage": 30 + }, + { + "color": "blue", + "percentage": 25 + }, + { + "color": "black", + "percentage": 15 + }, + { + "color": "red", + "percentage": 30 + } + ], + "video": null, + "video_duration": "01:15" + }, + { + "date": "03/11/2024", + "heure": "09:00", + "performance": [ + { + "color": "green", + "percentage": 22 + }, + { + "color": "blue", + "percentage": 18 + }, + { + "color": "black", + "percentage": 25 + }, + { + "color": "red", + "percentage": 35 + } + ], + "video": null, + "video_duration": "00:45" + }, + { + "date": "06/11/2024", + "heure": "13:00", + "performance": [ + { + "color": "green", + "percentage": 29 + }, + { + "color": "blue", + "percentage": 19 + }, + { + "color": "black", + "percentage": 13 + }, + { + "color": "red", + "percentage": 39 + } + ], + "video": null, + "video_duration": "01:30" + }, + { + "date": "07/11/2024", + "heure": "17:00", + "performance": [ + { + "color": "green", + "percentage": 28 + }, + { + "color": "blue", + "percentage": 21 + }, + { + "color": "black", + "percentage": 14 + }, + { + "color": "red", + "percentage": 37 + } + ], + "video": null, + "video_duration": "01:10" + }, + { + "date": "08/11/2024", + "heure": "11:00", + "performance": [ + { + "color": "green", + "percentage": 32 + }, + { + "color": "blue", + "percentage": 18 + }, + { + "color": "black", + "percentage": 16 + }, + { + "color": "red", + "percentage": 34 + } + ], + "video": null, + "video_duration": "00:50" + }, + { + "date": "09/11/2024", + "heure": "12:00", + "performance": [ + { + "color": "green", + "percentage": 30 + }, + { + "color": "blue", + "percentage": 20 + }, + { + "color": "black", + "percentage": 20 + }, + { + "color": "red", + "percentage": 30 + } + ], + "video": null, + "video_duration": "01:15" + }, + { + "date": "10/11/2024", + "heure": "15:00", + "performance": [ + { + "color": "green", + "percentage": 30 + }, + { + "color": "blue", + "percentage": 20 + }, + { + "color": "black", + "percentage": 10 + }, + { + "color": "red", + "percentage": 40 + } + ], + "video": null, + "video_duration": "01:20" + }, + { + "date": "11/11/2024", + "heure": "09:00", + "performance": [ + { + "color": "green", + "percentage": 25 + }, + { + "color": "blue", + "percentage": 25 + }, + { + "color": "black", + "percentage": 15 + }, + { + "color": "red", + "percentage": 35 + } + ], + "video": null, + "video_duration": "01:10" + }, + { + "date": "12/11/2024", + "heure": "16:00", + "performance": [ + { + "color": "green", + "percentage": 20 + }, + { + "color": "blue", + "percentage": 30 + }, + { + "color": "black", + "percentage": 15 + }, + { + "color": "red", + "percentage": 35 + } + ], + "video": null, + "video_duration": "01:30" + }, + { + "date": "13/11/2024", + "heure": "18:00", + "performance": [ + { + "color": "green", + "percentage": 30 + }, + { + "color": "blue", + "percentage": 20 + }, + { + "color": "black", + "percentage": 10 + }, + { + "color": "red", + "percentage": 40 + } + ], + "video": null, + "video_duration": "01:00" + }, + { + "date": "14/11/2024", + "heure": "14:00", + "performance": [ + { + "color": "green", + "percentage": 25 + }, + { + "color": "blue", + "percentage": 15 + }, + { + "color": "black", + "percentage": 25 + }, + { + "color": "red", + "percentage": 35 + } + ], + "video": null, + "video_duration": "01:10" + }, + { + "date": "15/11/2024", + "heure": "13:00", + "performance": [ + { + "color": "green", + "percentage": 30 + }, + { + "color": "blue", + "percentage": 20 + }, + { + "color": "black", + "percentage": 10 + }, + { + "color": "red", + "percentage": 40 + } + ], + "video": null, + "video_duration": "01:20" + } +] \ No newline at end of file diff --git a/Interface/data/dataClara.json b/Interface/data/data2.json similarity index 93% rename from Interface/data/dataClara.json rename to Interface/data/data2.json index 3332f8cd73c8f8e28ab15c2807e16f29661e1c5d..1a01e052224a6f09a4d4ff490b37e609909a8ddd 100644 --- a/Interface/data/dataClara.json +++ b/Interface/data/data2.json @@ -95,30 +95,6 @@ "video": null, "video_duration": "00:45" }, - { - "date": "04/11/2024", - "heure": "16:00", - "performance": [ - { - "color": "green", - "percentage": 26 - }, - { - "color": "blue", - "percentage": 22 - }, - { - "color": "black", - "percentage": 18 - }, - { - "color": "red", - "percentage": 34 - } - ], - "video": null, - "video_duration": "01:20" - }, { "date": "05/11/2024", "heure": "10:00", diff --git a/Interface/data/dataPaulette.json b/Interface/data/data3.json similarity index 100% rename from Interface/data/dataPaulette.json rename to Interface/data/data3.json diff --git a/Interface/data/dataLisa.json b/Interface/data/dataLisa.json deleted file mode 100644 index b33cb54cc6c7f98c093ab4052360504ff7a57d6c..0000000000000000000000000000000000000000 --- a/Interface/data/dataLisa.json +++ /dev/null @@ -1,411 +0,0 @@ - - [ - { - "date": "30/10/2024", - "heure": "18:00", - "performance": [ - { - "color": "green", - "percentage": 30 - }, - { - "color": "blue", - "percentage": 20 - }, - { - "color": "black", - "percentage": 10 - }, - { - "color": "red", - "percentage": 40 - } - ], - "video": null, - "video_duration": "01:00" - }, - { - "date": "31/10/2024", - "heure": "19:00", - "performance": [ - { - "color": "green", - "percentage": 25 - }, - { - "color": "blue", - "percentage": 15 - }, - { - "color": "black", - "percentage": 20 - }, - { - "color": "red", - "percentage": 40 - } - ], - "video": null, - "video_duration": "01:05" - }, - { - "date": "01/11/2024", - "heure": "20:00", - "performance": [ - { - "color": "green", - "percentage": 28 - }, - { - "color": "blue", - "percentage": 18 - }, - { - "color": "black", - "percentage": 12 - }, - { - "color": "red", - "percentage": 42 - } - ], - "video": null, - "video_duration": "01:10" - }, - { - "date": "02/11/2024", - "heure": "14:00", - "performance": [ - { - "color": "green", - "percentage": 30 - }, - { - "color": "blue", - "percentage": 25 - }, - { - "color": "black", - "percentage": 15 - }, - { - "color": "red", - "percentage": 30 - } - ], - "video": null, - "video_duration": "01:15" - }, - { - "date": "03/11/2024", - "heure": "09:00", - "performance": [ - { - "color": "green", - "percentage": 22 - }, - { - "color": "blue", - "percentage": 18 - }, - { - "color": "black", - "percentage": 25 - }, - { - "color": "red", - "percentage": 35 - } - ], - "video": null, - "video_duration": "00:45" - }, - { - "date": "04/11/2024", - "heure": "16:00", - "performance": [ - { - "color": "green", - "percentage": 26 - }, - { - "color": "blue", - "percentage": 22 - }, - { - "color": "black", - "percentage": 18 - }, - { - "color": "red", - "percentage": 34 - } - ], - "video": null, - "video_duration": "01:20" - }, - { - "date": "05/11/2024", - "heure": "10:00", - "performance": [ - { - "color": "green", - "percentage": 33 - }, - { - "color": "blue", - "percentage": 20 - }, - { - "color": "black", - "percentage": 17 - }, - { - "color": "red", - "percentage": 30 - } - ], - "video": null, - "video_duration": "01:00" - }, - { - "date": "06/11/2024", - "heure": "13:00", - "performance": [ - { - "color": "green", - "percentage": 29 - }, - { - "color": "blue", - "percentage": 19 - }, - { - "color": "black", - "percentage": 13 - }, - { - "color": "red", - "percentage": 39 - } - ], - "video": null, - "video_duration": "01:30" - }, - { - "date": "07/11/2024", - "heure": "17:00", - "performance": [ - { - "color": "green", - "percentage": 28 - }, - { - "color": "blue", - "percentage": 21 - }, - { - "color": "black", - "percentage": 14 - }, - { - "color": "red", - "percentage": 37 - } - ], - "video": null, - "video_duration": "01:10" - }, - { - "date": "08/11/2024", - "heure": "11:00", - "performance": [ - { - "color": "green", - "percentage": 32 - }, - { - "color": "blue", - "percentage": 18 - }, - { - "color": "black", - "percentage": 16 - }, - { - "color": "red", - "percentage": 34 - } - ], - "video": null, - "video_duration": "00:50" - }, - { - "date": "09/11/2024", - "heure": "12:00", - "performance": [ - { - "color": "green", - "percentage": 30 - }, - { - "color": "blue", - "percentage": 20 - }, - { - "color": "black", - "percentage": 20 - }, - { - "color": "red", - "percentage": 30 - } - ], - "video": null, - "video_duration": "01:15" - }, - { - "date": "10/11/2024", - "heure": "15:00", - "performance": [ - { - "color": "green", - "percentage": 30 - }, - { - "color": "blue", - "percentage": 20 - }, - { - "color": "black", - "percentage": 10 - }, - { - "color": "red", - "percentage": 40 - } - ], - "video": null, - "video_duration": "01:20" - }, - { - "date": "11/11/2024", - "heure": "09:00", - "performance": [ - { - "color": "green", - "percentage": 25 - }, - { - "color": "blue", - "percentage": 25 - }, - { - "color": "black", - "percentage": 15 - }, - { - "color": "red", - "percentage": 35 - } - ], - "video": null, - "video_duration": "01:10" - }, - { - "date": "12/11/2024", - "heure": "16:00", - "performance": [ - { - "color": "green", - "percentage": 20 - }, - { - "color": "blue", - "percentage": 30 - }, - { - "color": "black", - "percentage": 15 - }, - { - "color": "red", - "percentage": 35 - } - ], - "video": null, - "video_duration": "01:30" - }, - { - "date": "13/11/2024", - "heure": "18:00", - "performance": [ - { - "color": "green", - "percentage": 30 - }, - { - "color": "blue", - "percentage": 20 - }, - { - "color": "black", - "percentage": 10 - }, - { - "color": "red", - "percentage": 40 - } - ], - "video": null, - "video_duration": "01:00" - }, - { - "date": "14/11/2024", - "heure": "14:00", - "performance": [ - { - "color": "green", - "percentage": 25 - }, - { - "color": "blue", - "percentage": 15 - }, - { - "color": "black", - "percentage": 25 - }, - { - "color": "red", - "percentage": 35 - } - ], - "video": null, - "video_duration": "01:10" - }, - { - "date": "15/11/2024", - "heure": "13:00", - "performance": [ - { - "color": "green", - "percentage": 30 - }, - { - "color": "blue", - "percentage": 20 - }, - { - "color": "black", - "percentage": 10 - }, - { - "color": "red", - "percentage": 40 - } - ], - "video": null, - "video_duration": "01:20" - } - ] \ No newline at end of file diff --git a/Interface/data/infoPlayers.json b/Interface/data/infoPlayers.json new file mode 100644 index 0000000000000000000000000000000000000000..db45e22b19bffbc65c256e9bd53cf7e60866f43b --- /dev/null +++ b/Interface/data/infoPlayers.json @@ -0,0 +1,35 @@ +[ + { + "playerId": 1, + "playerName": "Martin", + "position": "R4", + "birth": "2025-02-24", + "taille": null, + "poids": null, + "attaque": 560, + "block": 100, + "comments": "bizou" + }, + { + "playerId": 2, + "playerName": "Annelise Samson", + "position": "Centrale", + "birth": "2003-06-27", + "taille": 100, + "poids": 76, + "attaque": 243, + "block": 8000, + "comments": "" + }, + { + "playerId": 3, + "playerName": "Jérémy", + "position": null, + "birth": null, + "taille": null, + "poids": null, + "attaque": null, + "block": null, + "comments": "" + } +] \ No newline at end of file diff --git a/Interface/data/photos/player2.jpg b/Interface/data/photos/player2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..70483bdf2e5e3447665eb057a8562cd779b6866d Binary files /dev/null and b/Interface/data/photos/player2.jpg differ diff --git a/Interface/data/player1/.DS_Store b/Interface/data/player1/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..2f2ca3238bd374533d2ff307523d092bfe216b6b Binary files /dev/null and b/Interface/data/player1/.DS_Store differ diff --git a/Interface/data/player1/data1.json b/Interface/data/player1/data1.json new file mode 100644 index 0000000000000000000000000000000000000000..31d171061967c83f895cef27e3236b8ad8139dd9 --- /dev/null +++ b/Interface/data/player1/data1.json @@ -0,0 +1,277 @@ +[ + { + "id": 8, + "date": "05/11/2024", + "heure": "10:00", + "performance": [ + { + "color": "green", + "percentage": 33 + }, + { + "color": "blue", + "percentage": 20 + }, + { + "color": "black", + "percentage": 17 + }, + { + "color": "red", + "percentage": 30 + } + ], + "video": "/Users/julieautuoro/nekoma-tech/interface/data/player1/videos/P1_S8.mp4", + "video_duration": "01:00" + }, + { + "id": 9, + "date": "06/11/2024", + "heure": "13:00", + "performance": [ + { + "color": "green", + "percentage": 29 + }, + { + "color": "blue", + "percentage": 19 + }, + { + "color": "black", + "percentage": 13 + }, + { + "color": "red", + "percentage": 39 + } + ], + "video": "/Users/julieautuoro/nekoma-tech/interface/data/player1/videos/P1_S9.mp4", + "video_duration": "01:30" + }, + { + "id": 10, + "date": "07/11/2024", + "heure": "17:00", + "performance": [ + { + "color": "green", + "percentage": 28 + }, + { + "color": "blue", + "percentage": 21 + }, + { + "color": "black", + "percentage": 14 + }, + { + "color": "red", + "percentage": 37 + } + ], + "video": "/Users/julieautuoro/nekoma-tech/interface/data/player1/videos/P1_S10.mp4", + "video_duration": "01:10" + }, + { + "id": 11, + "date": "08/11/2024", + "heure": "11:00", + "performance": [ + { + "color": "green", + "percentage": 32 + }, + { + "color": "blue", + "percentage": 18 + }, + { + "color": "black", + "percentage": 16 + }, + { + "color": "red", + "percentage": 34 + } + ], + "video": "/Users/julieautuoro/nekoma-tech/interface/data/player1/videos/P1_S11.mp4", + "video_duration": "00:50" + }, + { + "id": 12, + "date": "09/11/2024", + "heure": "12:00", + "performance": [ + { + "color": "green", + "percentage": 30 + }, + { + "color": "blue", + "percentage": 20 + }, + { + "color": "black", + "percentage": 20 + }, + { + "color": "red", + "percentage": 30 + } + ], + "video": "/Users/julieautuoro/nekoma-tech/interface/data/player1/videos/P1_S12.mp4", + "video_duration": "01:15" + }, + { + "id": 13, + "date": "10/11/2024", + "heure": "15:00", + "performance": [ + { + "color": "green", + "percentage": 30 + }, + { + "color": "blue", + "percentage": 20 + }, + { + "color": "black", + "percentage": 10 + }, + { + "color": "red", + "percentage": 40 + } + ], + "video": "/Users/julieautuoro/nekoma-tech/interface/data/player1/videos/P1_S13.mp4", + "video_duration": "01:20" + }, + { + "id": 14, + "date": "11/11/2024", + "heure": "09:00", + "performance": [ + { + "color": "green", + "percentage": 25 + }, + { + "color": "blue", + "percentage": 25 + }, + { + "color": "black", + "percentage": 15 + }, + { + "color": "red", + "percentage": 35 + } + ], + "video": null, + "video_duration": "01:10" + }, + { + "id": 15, + "date": "12/11/2024", + "heure": "16:00", + "performance": [ + { + "color": "green", + "percentage": 20 + }, + { + "color": "blue", + "percentage": 30 + }, + { + "color": "black", + "percentage": 15 + }, + { + "color": "red", + "percentage": 35 + } + ], + "video": null, + "video_duration": "01:30" + }, + { + "id": 16, + "date": "13/11/2024", + "heure": "18:00", + "performance": [ + { + "color": "green", + "percentage": 30 + }, + { + "color": "blue", + "percentage": 20 + }, + { + "color": "black", + "percentage": 10 + }, + { + "color": "red", + "percentage": 40 + } + ], + "video": null, + "video_duration": "01:00" + }, + { + "id": 17, + "date": "14/11/2024", + "heure": "14:00", + "performance": [ + { + "color": "green", + "percentage": 25 + }, + { + "color": "blue", + "percentage": 15 + }, + { + "color": "black", + "percentage": 25 + }, + { + "color": "red", + "percentage": 35 + } + ], + "video": null, + "video_duration": "01:10" + }, + { + "id": 18, + "date": "15/11/2024", + "heure": "13:00", + "performance": [ + { + "color": "green", + "percentage": 30 + }, + { + "color": "blue", + "percentage": 20 + }, + { + "color": "black", + "percentage": 10 + }, + { + "color": "red", + "percentage": 40 + } + ], + "video": null, + "video_duration": "01:20" + } +] \ No newline at end of file diff --git a/Interface/data/player1/player1.jpg b/Interface/data/player1/player1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..70483bdf2e5e3447665eb057a8562cd779b6866d Binary files /dev/null and b/Interface/data/player1/player1.jpg differ diff --git a/Interface/data/player1/videos/.DS_Store b/Interface/data/player1/videos/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 Binary files /dev/null and b/Interface/data/player1/videos/.DS_Store differ diff --git a/Interface/data/player1/videos/P1_S1.mp4 b/Interface/data/player1/videos/P1_S1.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..3d746e512ea2ef71476e434b4b3bdd487cf1c723 Binary files /dev/null and b/Interface/data/player1/videos/P1_S1.mp4 differ diff --git a/Interface/data/player1/videos/P1_S10.mp4 b/Interface/data/player1/videos/P1_S10.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..5554faf8db639720bea011113349fce2fc5fd8b6 Binary files /dev/null and b/Interface/data/player1/videos/P1_S10.mp4 differ diff --git a/Interface/data/player1/videos/P1_S11.mp4 b/Interface/data/player1/videos/P1_S11.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..ea5ea0549b42f3696308729bd9d15d9030f8d8ea Binary files /dev/null and b/Interface/data/player1/videos/P1_S11.mp4 differ diff --git a/Interface/data/player1/videos/P1_S12.mp4 b/Interface/data/player1/videos/P1_S12.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..ef21f17383eeae1888e87684a5aaea2fa856f68e Binary files /dev/null and b/Interface/data/player1/videos/P1_S12.mp4 differ diff --git a/Interface/data/player1/videos/P1_S13.mp4 b/Interface/data/player1/videos/P1_S13.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..e14e8f5c1ef241889021c862961d67749d20789d Binary files /dev/null and b/Interface/data/player1/videos/P1_S13.mp4 differ diff --git a/Interface/data/player1/videos/P1_S14.mp4 b/Interface/data/player1/videos/P1_S14.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..378abfba0bf06292575c6c67a086c8bbeaec6116 Binary files /dev/null and b/Interface/data/player1/videos/P1_S14.mp4 differ diff --git a/Interface/data/player1/videos/P1_S15.mp4 b/Interface/data/player1/videos/P1_S15.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..ce2c5c12f7ce326f2feddc65e503c240aa1ea33a Binary files /dev/null and b/Interface/data/player1/videos/P1_S15.mp4 differ diff --git a/Interface/data/player1/videos/P1_S16.mp4 b/Interface/data/player1/videos/P1_S16.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..f16d0bafcacf52edc7862ae66810002de052f4ef Binary files /dev/null and b/Interface/data/player1/videos/P1_S16.mp4 differ diff --git a/Interface/data/player1/videos/P1_S17.mp4 b/Interface/data/player1/videos/P1_S17.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..db94d75a8b4cefa978c256db3ef4ff1a2fdc8927 Binary files /dev/null and b/Interface/data/player1/videos/P1_S17.mp4 differ diff --git a/Interface/data/player1/videos/P1_S18.mp4 b/Interface/data/player1/videos/P1_S18.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..d4224ff4d214a36e31361306fcd1c034b8d793bb Binary files /dev/null and b/Interface/data/player1/videos/P1_S18.mp4 differ diff --git a/Interface/data/player1/videos/P1_S19.mp4 b/Interface/data/player1/videos/P1_S19.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..d08c4103fa459982d3cd507f03eca145d0ad3928 Binary files /dev/null and b/Interface/data/player1/videos/P1_S19.mp4 differ diff --git a/Interface/data/player1/videos/P1_S2.mp4 b/Interface/data/player1/videos/P1_S2.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..0ee84e0e2be4d4e87578641ac27310115c10ecb4 Binary files /dev/null and b/Interface/data/player1/videos/P1_S2.mp4 differ diff --git a/Interface/data/player1/videos/P1_S20.mp4 b/Interface/data/player1/videos/P1_S20.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..0bcf9378a7e636554e9b483831538e78de8c7bd7 Binary files /dev/null and b/Interface/data/player1/videos/P1_S20.mp4 differ diff --git a/Interface/data/player1/videos/P1_S21.mp4 b/Interface/data/player1/videos/P1_S21.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..0372b05d94b20138d9f4e96c6623580511222c95 Binary files /dev/null and b/Interface/data/player1/videos/P1_S21.mp4 differ diff --git a/Interface/data/player1/videos/P1_S22.mp4 b/Interface/data/player1/videos/P1_S22.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..c3a3e95890c5f9841ba46af0b93e0ce9965ab7d2 Binary files /dev/null and b/Interface/data/player1/videos/P1_S22.mp4 differ diff --git a/Interface/data/player1/videos/P1_S23.mp4 b/Interface/data/player1/videos/P1_S23.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..a416ad839f175f0d91baeef4f6197353503b7f14 Binary files /dev/null and b/Interface/data/player1/videos/P1_S23.mp4 differ diff --git a/Interface/data/player1/videos/P1_S3.mp4 b/Interface/data/player1/videos/P1_S3.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..5e26bf41846e8ea36275a3b0f9ca07903c4bf218 Binary files /dev/null and b/Interface/data/player1/videos/P1_S3.mp4 differ diff --git a/Interface/data/player1/videos/P1_S4.mp4 b/Interface/data/player1/videos/P1_S4.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..5ad83325919f1cbecc880df9dc5d1d258178a200 Binary files /dev/null and b/Interface/data/player1/videos/P1_S4.mp4 differ diff --git a/Interface/data/player1/videos/P1_S5.mp4 b/Interface/data/player1/videos/P1_S5.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..c0d8c188292adc8bcf77dab19f7e93abbd2971f3 Binary files /dev/null and b/Interface/data/player1/videos/P1_S5.mp4 differ diff --git a/Interface/data/player1/videos/P1_S6.mp4 b/Interface/data/player1/videos/P1_S6.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..9f9efa0751ffa57d9b37edad9aaa2501d901275c Binary files /dev/null and b/Interface/data/player1/videos/P1_S6.mp4 differ diff --git a/Interface/data/player1/videos/P1_S7.mp4 b/Interface/data/player1/videos/P1_S7.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..0bff25908bb3468cae495e3a2e564a8f3a7ea731 Binary files /dev/null and b/Interface/data/player1/videos/P1_S7.mp4 differ diff --git a/Interface/data/player1/videos/P1_S8.mp4 b/Interface/data/player1/videos/P1_S8.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..143632619f31403e24965d5de264a49479a3cce2 Binary files /dev/null and b/Interface/data/player1/videos/P1_S8.mp4 differ diff --git a/Interface/data/player1/videos/P1_S9.mp4 b/Interface/data/player1/videos/P1_S9.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..07c0c3f4dc6b8dcb868dc780412937a1381f149a Binary files /dev/null and b/Interface/data/player1/videos/P1_S9.mp4 differ diff --git a/Interface/default-avatar.jpg b/Interface/default-avatar.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b9b97bf4cbb0ab970342a7cf6aeac81d82596be6 Binary files /dev/null and b/Interface/default-avatar.jpg differ diff --git a/Interface/edit-icon.png b/Interface/edit-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1ed8ccb015081b0289fae98658d5244edbcf3743 Binary files /dev/null and b/Interface/edit-icon.png differ diff --git a/Interface/edit-player.html b/Interface/edit-player.html new file mode 100644 index 0000000000000000000000000000000000000000..58cc66b4243a198af46253bd00ec2e8aa4bbcd97 --- /dev/null +++ b/Interface/edit-player.html @@ -0,0 +1,94 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8" /> + <meta http-equiv="X-UA-Compatible" content="IE=edge" /> + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> + <meta name="description" content="" /> + <meta name="author" content="" /> + <title>Edit Player - SB Admin</title> + <link href="https://cdn.jsdelivr.net/npm/simple-datatables@7.1.2/dist/style.min.css" rel="stylesheet" /> + <link href="css/edit-styles.css" rel="stylesheet" /> + <script src="https://use.fontawesome.com/releases/v6.3.0/js/all.js" crossorigin="anonymous"></script> + </head> + <body class="sb-nav-fixed"> + <div id="nav"></div> + <div id="layoutSidenav"> + <div id="menu"></div> + <div id="layoutSidenav_content"> + <main> + <div class="container-fluid px-4"> + <h1 class="mt-4">Modifier la joueuse</h1> + + <div class="player-header"> + <div class="photo-section"> + <img id="editPlayerPhoto" src="default-avatar.jpg" alt="Photo de la joueuse" class="player-photo"> + <button id="changePhoto">Modifier la photo</button> + </div> + <div class="name-section"> + <textarea id="editPlayerName" placeholder="Entrez le nom..."></textarea> + </div> + </div> + + <div class="player-details edit-player-details"> + <div class="detail-item"> + <B>Position :</B> + <select id="editPositionPlayed"> + <option value="Choisir une position">Choisir une position</option> + <option value="Libéro">Libero</option> + <option value="R4">R4</option> + <option value="Passeuse">Passeuse</option> + <option value="Centrale">Centrale</option> + <option value="Pointue">Pointue</option> + </select> + </div> + + <div class="detail-item"> + <B>Date de naissance :</B> + <input type="date" id="editPlayerBirthDate"> + </div> + + <div class="detail-item"> + <B>Taille :</B> + <input type="number" id="editPlayerHeight" placeholder="Taille"> + <span class="unit">cm</span> + </div> + + <div class="detail-item"> + <B>Poids :</B> + <input type="number" id="editPlayerWeight" placeholder="Poids"> + <span class="unit">kg</span> + </div> + + <div class="detail-item"> + <B>Attaque :</B> + <input type="number" id="editPlayerAttack" placeholder="Attack"> + <span class="unit">cm</span> + </div> + + <div class="detail-item"> + <B>Block :</B> + <input type="number" id="editPlayerBlockHeight" placeholder="Block"> + <span class="unit">cm</span> + </div> + </div> + + <div class="comment-section"> + <B>Commentaires :</B> + <textarea id="editPlayerComments" placeholder="Ajoutez un commentaire..."></textarea> + </div> + + <div class="edit-buttons"> + <button id="saveChanges">Enregistrer</button> + <button id="cancelChanges">Annuler</button> + </div> + + </div> + </main> + <div id="footer"></div> + </div> + </div> + <script src="js/edit-players.js"></script> + <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script> + </body> +</html> \ No newline at end of file diff --git a/Interface/icons/.DS_Store b/Interface/icons/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..2ac0e949f786447818625ece50913fd647c6f128 Binary files /dev/null and b/Interface/icons/.DS_Store differ diff --git a/Interface/icons/Ball-icon.png b/Interface/icons/Ball-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a0df276e39fd9d296b44c9fd4030c7cc297bb019 Binary files /dev/null and b/Interface/icons/Ball-icon.png differ diff --git a/Interface/icons/Volatile-icon.png b/Interface/icons/Volatile-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c3e447de1fd38e44eb650d06b7097afb210940f9 Binary files /dev/null and b/Interface/icons/Volatile-icon.png differ diff --git a/Interface/icons/ball-icon.svg b/Interface/icons/ball-icon.svg new file mode 100644 index 0000000000000000000000000000000000000000..ff138790db496a8ef6f856ebe08467682a5dfaa8 --- /dev/null +++ b/Interface/icons/ball-icon.svg @@ -0,0 +1,152 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" + "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<svg version="1.0" xmlns="http://www.w3.org/2000/svg" + width="900.000000pt" height="834.000000pt" viewBox="0 0 900.000000 834.000000" + preserveAspectRatio="xMidYMid meet"> +<metadata> +Created by potrace 1.10, written by Peter Selinger 2001-2011 +</metadata> +<g transform="translate(0.000000,834.000000) scale(0.100000,-0.100000)" +fill="#000000" stroke="none"> +<path d="M4444 7790 c-12 -4 -31 -21 -43 -36 -21 -26 -21 -32 -21 -498 0 -522 +-2 -498 66 -525 37 -15 77 -1 111 39 l22 25 1 463 0 462 -32 35 c-36 37 -71 +49 -104 35z"/> +<path d="M3920 6928 c-19 -5 -62 -16 -95 -25 -125 -33 -363 -117 -405 -144 -8 +-5 -24 -13 -35 -18 -197 -87 -462 -256 -634 -406 -112 -97 -308 -306 -389 +-413 -93 -123 -152 -209 -152 -219 0 -4 -6 -14 -14 -22 -34 -40 -164 -298 +-209 -416 -8 -22 -29 -74 -45 -115 -28 -69 -37 -98 -72 -228 -22 -84 26 -152 +108 -152 51 0 98 43 107 98 4 20 12 53 19 72 7 19 21 62 31 95 9 33 21 67 26 +75 5 8 12 22 15 30 3 8 12 30 20 48 8 17 20 47 28 65 18 42 84 178 96 197 5 8 +37 62 71 120 56 94 165 248 194 275 6 6 28 32 49 58 123 155 353 349 596 503 +99 63 273 149 395 196 117 46 185 69 225 78 151 33 185 46 215 82 43 51 25 +132 -35 163 -32 17 -58 18 -110 3z"/> +<path d="M4967 6909 c-40 -23 -59 -98 -36 -142 15 -26 50 -56 67 -57 13 0 53 +-11 172 -48 223 -70 450 -178 640 -305 165 -110 272 -199 418 -347 87 -88 242 +-270 242 -284 0 -3 20 -32 45 -65 25 -32 45 -62 45 -66 0 -4 13 -26 28 -49 15 +-22 38 -61 50 -86 13 -25 27 -52 32 -60 16 -25 100 -210 100 -219 0 -5 12 -33 +26 -62 15 -29 31 -67 35 -83 4 -17 17 -62 29 -101 11 -38 23 -86 27 -105 13 +-73 70 -117 136 -105 67 13 95 69 78 160 -19 101 -63 241 -82 260 -5 5 -9 17 +-9 27 0 18 -11 47 -61 155 -16 35 -29 69 -29 77 0 8 -4 17 -8 20 -5 3 -28 42 +-51 88 -43 86 -47 93 -93 166 -16 24 -28 45 -28 47 0 14 -165 239 -221 300 +-20 22 -63 69 -95 105 -76 85 -75 84 -229 219 -82 72 -365 271 -385 271 -5 0 +-25 10 -43 23 -49 34 -259 134 -352 170 -93 35 -123 45 -175 60 -30 9 -77 23 +-103 32 -54 17 -143 19 -170 4z"/> +<path d="M4437 6544 c-4 -4 -67 -11 -140 -15 -133 -8 -256 -26 -357 -52 -145 +-39 -205 -57 -265 -83 -16 -7 -55 -22 -85 -35 -186 -74 -390 -198 -577 -350 +-185 -151 -404 -409 -520 -614 -58 -103 -164 -329 -191 -410 -53 -155 -63 +-195 -82 -335 -6 -41 -16 -95 -22 -120 -20 -83 -22 -389 -4 -518 42 -292 48 +-320 111 -507 110 -329 287 -615 537 -868 310 -314 611 -490 1063 -622 189 +-55 503 -84 718 -67 198 16 402 48 445 71 9 5 36 12 59 16 24 4 45 11 49 16 3 +5 14 9 24 9 11 0 34 6 52 14 18 8 53 22 78 31 89 35 296 140 358 182 35 24 66 +43 69 43 8 0 157 114 228 174 131 110 326 329 402 451 158 253 237 419 299 +630 24 83 46 177 53 230 4 28 10 55 14 61 3 6 11 92 17 190 11 184 1 485 -19 +576 -6 24 -17 77 -26 118 -20 91 -53 209 -66 232 -5 10 -9 25 -9 33 0 9 -15 +46 -34 83 -19 37 -48 96 -65 132 -17 36 -46 92 -66 125 -19 33 -38 67 -42 75 +-4 8 -27 44 -51 80 -204 298 -456 533 -764 713 -101 59 -303 152 -398 184 +-200 65 -368 99 -565 114 -71 5 -150 12 -175 15 -25 3 -48 2 -53 -2z m358 +-209 c55 -9 114 -20 130 -25 17 -4 45 -11 62 -15 18 -4 35 -10 38 -15 3 -4 +-55 -37 -128 -74 -72 -36 -163 -86 -200 -111 -38 -25 -71 -45 -74 -45 -7 0 +-128 -93 -131 -102 -2 -4 -38 -36 -80 -71 -188 -156 -422 -426 -546 -630 -11 +-18 -47 -75 -81 -127 -59 -91 -72 -115 -128 -240 -41 -92 -58 -132 -78 -195 +-11 -33 -24 -73 -30 -90 -17 -50 -40 -128 -49 -170 -25 -115 -32 -134 -51 +-140 -10 -4 -29 1 -41 9 -12 9 -32 16 -43 16 -21 0 -96 23 -152 46 -106 44 +-109 46 -212 100 -94 49 -105 65 -86 124 7 25 21 71 29 103 33 117 49 173 62 +202 6 17 20 50 29 75 21 57 75 165 127 255 23 39 48 84 57 100 21 37 142 222 +167 254 202 257 425 464 659 611 39 24 126 72 195 107 l125 63 165 0 c98 0 +204 -6 265 -15z m-1035 -117 c0 -7 -13 -22 -29 -33 -126 -89 -311 -276 -467 +-471 -45 -58 -186 -268 -222 -334 -8 -14 -43 -81 -79 -150 -36 -69 -69 -130 +-73 -135 -5 -6 -15 -28 -23 -50 -8 -22 -29 -80 -47 -130 -17 -49 -36 -108 -41 +-130 -16 -72 -35 -134 -42 -141 -8 -8 -65 29 -133 86 -121 103 -144 125 -144 +140 0 8 9 40 21 70 11 30 25 69 30 85 5 17 17 44 27 62 9 17 28 53 42 80 13 +26 44 80 67 120 24 39 43 74 43 78 0 3 41 61 92 128 84 111 126 162 199 236 +44 44 180 165 197 175 10 5 23 16 31 24 66 65 433 267 549 301 1 1 2 -5 2 -11z +m1641 -73 c30 -13 77 -38 104 -55 28 -16 57 -33 65 -37 24 -11 171 -113 218 +-151 23 -19 42 -39 42 -46 0 -6 -28 -19 -63 -29 -34 -10 -75 -25 -90 -33 -16 +-7 -35 -14 -42 -14 -7 0 -26 -7 -42 -15 -15 -8 -50 -24 -78 -36 -311 -132 +-521 -290 -756 -567 -99 -117 -152 -199 -219 -342 -11 -25 -28 -58 -35 -73 -8 +-16 -15 -43 -15 -60 0 -29 -6 -51 -39 -147 -7 -19 -19 -66 -26 -105 -19 -103 +-30 -125 -60 -125 -15 0 -36 -5 -48 -12 -12 -6 -58 -18 -102 -25 -44 -8 -105 +-18 -135 -24 -88 -17 -348 -23 -393 -9 -38 11 -39 12 -32 48 4 20 10 42 15 47 +4 6 10 28 13 50 10 66 41 164 103 328 26 67 102 230 127 272 46 76 85 134 104 +155 13 14 23 28 23 32 0 8 79 119 155 218 28 35 104 120 170 188 66 68 123 +129 127 137 8 12 232 185 242 185 2 0 32 18 65 40 103 69 313 168 451 214 63 +21 90 20 151 -9z m655 -498 c81 -88 208 -256 238 -317 4 -8 29 -55 56 -105 +104 -190 156 -323 193 -495 8 -41 21 -100 28 -130 7 -32 14 -167 16 -325 4 +-223 2 -282 -11 -338 -9 -38 -16 -83 -16 -102 0 -33 -13 -54 -24 -37 -7 11 +-23 105 -36 199 -5 40 -13 89 -19 110 -5 21 -17 74 -26 118 -9 44 -23 94 -30 +110 -7 17 -16 41 -18 55 -5 25 -30 98 -46 135 -5 11 -19 45 -31 75 -28 70 -69 +161 -80 180 -5 8 -21 39 -36 69 -14 29 -43 82 -65 118 -21 35 -39 66 -39 69 0 +6 -21 35 -65 89 -20 25 -101 128 -132 170 -25 33 -149 168 -197 215 -31 30 +-56 60 -56 67 0 8 12 18 28 23 15 6 35 15 44 20 10 6 23 10 29 10 6 0 25 6 42 +14 34 15 134 43 198 55 3 0 28 -23 55 -52z m-475 -264 c58 -60 134 -142 170 +-183 35 -41 71 -82 80 -91 31 -31 112 -148 128 -184 5 -11 21 -37 35 -58 14 +-21 26 -44 26 -52 0 -8 4 -16 8 -19 12 -7 90 -166 147 -301 58 -138 114 -346 +140 -525 8 -52 19 -113 25 -135 7 -26 10 -117 7 -260 -3 -206 -15 -321 -40 +-389 -21 -58 -162 -258 -242 -345 -117 -127 -148 -143 -125 -65 13 45 7 462 +-9 584 -14 112 -38 235 -49 256 -5 11 -13 40 -16 66 -4 26 -11 50 -17 53 -5 4 +-9 15 -9 26 0 20 -23 91 -60 189 -12 30 -25 66 -30 80 -4 14 -20 49 -34 78 +-15 29 -46 95 -71 147 -119 254 -293 492 -537 739 -70 71 -128 132 -128 135 0 +4 37 43 83 87 87 86 212 183 287 223 25 13 54 30 65 38 39 26 58 15 166 -94z +m-614 -512 c54 -54 115 -117 136 -140 43 -46 197 -238 197 -245 0 -3 19 -33 +42 -68 41 -61 103 -173 148 -268 58 -122 79 -170 99 -220 12 -30 26 -64 30 +-75 16 -39 32 -91 48 -145 8 -30 21 -77 29 -105 42 -142 68 -363 68 -580 0 +-208 -6 -267 -50 -482 -4 -19 -98 -90 -174 -132 -110 -59 -247 -124 -329 -155 +-51 -20 -66 -10 -49 33 35 88 60 489 48 742 -16 299 -49 427 -178 674 -8 17 +-19 32 -24 33 -4 2 -8 9 -8 16 0 35 -190 278 -349 446 l-71 75 3 65 c4 84 17 +133 73 283 27 70 127 267 157 308 16 22 35 39 42 39 8 0 58 -44 112 -99z +m-2479 -285 c40 -35 200 -156 207 -156 2 0 33 -20 69 -45 37 -25 68 -45 71 +-45 2 0 23 -12 47 -27 24 -16 52 -34 63 -41 66 -41 210 -105 290 -127 33 -10 +71 -22 84 -27 32 -12 157 -38 251 -51 97 -14 462 -14 565 0 106 15 223 38 258 +52 42 16 97 14 97 -4 0 -8 15 -30 33 -48 133 -139 276 -324 343 -445 l29 -53 +-24 -20 c-13 -10 -33 -19 -45 -19 -11 -1 -32 -7 -46 -15 -14 -8 -38 -14 -53 +-15 -16 0 -38 -5 -50 -12 -28 -15 -209 -51 -342 -68 -93 -12 -489 -11 -590 1 +-206 25 -329 47 -372 65 -17 8 -37 14 -45 14 -16 0 -72 18 -198 62 -73 26 +-303 134 -365 171 -190 115 -365 254 -385 309 -21 55 -24 269 -6 391 9 59 16 +125 16 145 0 71 25 73 98 8z m-8 -884 c0 -8 154 -112 165 -112 3 0 24 -12 48 +-27 47 -30 233 -123 247 -123 5 0 21 -6 37 -14 15 -8 47 -22 71 -30 23 -9 59 +-22 80 -30 20 -8 64 -21 97 -31 33 -9 74 -21 92 -26 80 -24 202 -46 383 -69 +121 -15 681 -9 760 9 30 7 87 19 125 27 39 8 93 21 120 29 28 7 79 21 115 30 +36 9 80 23 99 32 32 13 36 13 55 -6 30 -31 49 -180 50 -406 l1 -189 -65 -19 +c-89 -25 -134 -36 -210 -52 -36 -8 -85 -19 -110 -24 -203 -47 -684 -45 -900 3 +-36 8 -101 22 -145 31 -44 10 -92 22 -107 27 -14 5 -41 14 -60 18 -122 32 +-377 144 -485 213 -24 15 -45 27 -48 27 -9 0 -150 99 -190 133 -22 19 -51 54 +-63 78 -13 24 -33 62 -45 84 -59 106 -163 386 -153 412 6 14 36 18 36 5z m768 +-1088 c18 -8 41 -14 50 -14 10 0 22 -4 27 -9 14 -13 145 -48 260 -71 33 -6 74 +-15 90 -20 17 -5 75 -14 130 -20 55 -6 129 -15 165 -21 145 -23 663 5 748 41 +13 6 35 10 49 10 23 0 72 12 169 41 17 5 41 9 53 9 23 0 24 -1 16 -92 -4 -50 +-11 -103 -17 -117 -5 -14 -14 -51 -20 -81 -19 -107 1 -99 -333 -140 -91 -11 +-254 -11 -330 1 -33 5 -96 14 -140 19 -44 5 -93 13 -108 19 -16 6 -42 11 -58 +11 -16 0 -37 4 -47 9 -9 6 -57 22 -107 37 -49 15 -97 31 -105 35 -8 4 -40 17 +-70 29 -56 23 -163 73 -190 90 -8 5 -53 32 -100 60 -139 85 -290 202 -290 226 +0 13 31 2 158 -52z"/> +<path d="M7088 4371 c-15 -3 -38 -16 -52 -28 -36 -32 -37 -114 -1 -158 l25 +-30 479 0 479 0 25 23 c13 13 32 38 42 56 18 33 18 34 -3 68 -49 78 -11 73 +-516 74 -248 0 -463 -2 -478 -5z"/> +<path d="M957 4352 c-62 -38 -60 -147 2 -189 l34 -23 451 0 c510 1 505 0 534 +73 12 33 13 44 2 78 -8 22 -26 49 -41 60 -26 18 -48 19 -491 19 -420 -1 -466 +-2 -491 -18z"/> +<path d="M1920 3772 c-46 -23 -69 -82 -53 -139 6 -21 19 -65 27 -98 32 -115 +59 -200 68 -209 4 -6 8 -19 8 -31 0 -12 7 -30 15 -41 8 -10 15 -25 15 -31 0 +-32 140 -311 209 -418 14 -22 30 -48 36 -57 116 -192 391 -497 570 -633 28 +-20 52 -41 55 -45 9 -14 180 -129 277 -188 101 -60 298 -159 368 -185 305 +-113 431 -143 485 -115 14 8 33 31 43 52 17 35 17 40 2 80 -17 43 -56 76 -92 +76 -11 0 -42 7 -69 15 -27 9 -71 23 -99 31 -54 17 -88 29 -175 64 -66 27 -283 +134 -325 161 -16 10 -37 22 -45 26 -42 19 -226 153 -335 243 -39 32 -232 225 +-270 270 -161 191 -238 309 -385 600 -9 17 -65 157 -85 210 -7 19 -21 62 -30 +95 -10 33 -24 78 -31 100 -8 23 -14 48 -14 58 0 9 -7 35 -17 58 -11 30 -25 45 +-49 55 -44 18 -62 18 -104 -4z"/> +<path d="M6948 3707 c-25 -21 -58 -97 -58 -135 0 -9 -12 -48 -26 -87 -14 -38 +-29 -83 -34 -100 -17 -64 -104 -254 -180 -390 -131 -238 -323 -471 -545 -664 +-167 -145 -298 -235 -488 -335 -85 -44 -207 -100 -257 -116 -14 -5 -50 -18 +-80 -30 -63 -24 -137 -47 -195 -60 -150 -33 -175 -52 -175 -130 0 -49 4 -60 +28 -83 23 -22 38 -27 78 -27 27 0 69 6 94 14 25 8 72 22 105 31 33 9 75 23 93 +31 18 8 39 14 47 14 14 0 66 20 118 46 16 8 33 14 39 14 16 0 268 125 311 154 +21 14 40 26 43 26 3 0 49 29 102 64 335 223 644 548 847 890 69 117 165 306 +165 325 0 5 6 22 14 38 26 52 46 104 46 118 0 7 6 26 14 42 8 15 21 53 30 83 +8 30 22 79 30 109 20 68 20 96 -1 131 -31 54 -116 68 -165 27z"/> +<path d="M4460 1763 c-8 -3 -25 -15 -37 -26 l-23 -20 0 -477 0 -477 23 -25 +c45 -52 121 -45 157 14 19 32 20 51 20 483 0 432 -1 451 -20 483 -27 43 -75 +61 -120 45z"/> +</g> +</svg> diff --git a/Interface/icons/default-avatar.jpg b/Interface/icons/default-avatar.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b9b97bf4cbb0ab970342a7cf6aeac81d82596be6 Binary files /dev/null and b/Interface/icons/default-avatar.jpg differ diff --git a/Interface/icons/edit-icon.png b/Interface/icons/edit-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1ed8ccb015081b0289fae98658d5244edbcf3743 Binary files /dev/null and b/Interface/icons/edit-icon.png differ diff --git a/Interface/icons/placeholder-thumbnail.jpeg b/Interface/icons/placeholder-thumbnail.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4b7827755bd159767b85e19c1cbcd634286b054b Binary files /dev/null and b/Interface/icons/placeholder-thumbnail.jpeg differ diff --git a/Interface/icons/poubelle.png b/Interface/icons/poubelle.png new file mode 100644 index 0000000000000000000000000000000000000000..33790dc7d2eeee8a482ec8359b4829c68dd0964e Binary files /dev/null and b/Interface/icons/poubelle.png differ diff --git a/Interface/icons/volatile-icon.svg b/Interface/icons/volatile-icon.svg new file mode 100644 index 0000000000000000000000000000000000000000..4cb1799c922ab12a5bf5412ade7a75ca04a630d3 --- /dev/null +++ b/Interface/icons/volatile-icon.svg @@ -0,0 +1,123 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" + "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<svg version="1.0" xmlns="http://www.w3.org/2000/svg" + width="900.000000pt" height="282.000000pt" viewBox="0 0 900.000000 282.000000" + preserveAspectRatio="xMidYMid meet"> +<metadata> +Created by potrace 1.10, written by Peter Selinger 2001-2011 +</metadata> +<g transform="translate(0.000000,282.000000) scale(0.100000,-0.100000)" +fill="#000000" stroke="none"> +<path d="M2607 2474 c-4 -4 -7 -72 -7 -151 l0 -144 28 3 27 3 0 145 c0 138 -1 +145 -20 148 -12 2 -24 0 -28 -4z"/> +<path d="M3740 2461 c-7 -13 -10 -315 -10 -908 0 -775 2 -892 15 -909 15 -19 +15 -19 35 5 20 23 20 34 18 918 -3 782 -5 895 -18 903 -22 14 -28 12 -40 -9z"/> +<path d="M7017 2463 c-12 -11 -8 -1831 3 -1838 6 -3 19 -3 30 0 20 6 20 16 20 +910 0 497 -3 910 -6 919 -6 16 -35 22 -47 9z"/> +<path d="M1783 2412 c-6 -10 -37 -79 -68 -152 -31 -73 -60 -141 -65 -149 -8 +-17 -31 -71 -53 -124 -7 -17 -21 -49 -30 -69 -17 -37 -29 -66 -60 -138 -8 -19 +-22 -52 -31 -72 -9 -21 -23 -53 -32 -73 -8 -19 -21 -50 -30 -70 -8 -19 -21 +-51 -29 -70 -19 -45 -41 -95 -60 -140 -35 -79 -49 -112 -62 -142 -7 -18 -20 +-48 -29 -68 -8 -19 -21 -50 -30 -70 -8 -19 -21 -50 -30 -70 -8 -19 -22 -52 +-31 -72 -9 -21 -23 -54 -31 -73 -37 -87 -57 -108 -68 -73 -3 10 -12 32 -19 48 +-14 30 -50 112 -87 195 -10 25 -26 61 -35 80 -8 19 -21 49 -27 65 -7 17 -21 +48 -31 70 -10 22 -24 56 -33 75 -8 19 -18 42 -22 51 -5 8 -34 76 -65 149 -31 +73 -60 141 -65 149 -4 9 -14 32 -22 51 -8 19 -22 52 -31 73 -9 20 -23 52 -31 +70 -8 17 -28 61 -45 97 -17 36 -31 69 -31 73 0 4 -14 38 -31 75 -17 37 -37 82 +-45 100 -53 123 -77 172 -86 178 -11 7 -36 -7 -42 -23 -4 -8 5 -41 20 -72 24 +-52 43 -95 81 -181 9 -19 19 -42 23 -51 5 -8 34 -76 65 -149 31 -73 60 -141 +65 -149 4 -9 14 -33 24 -53 9 -21 23 -55 32 -75 10 -21 20 -45 24 -54 5 -8 34 +-76 65 -149 31 -73 61 -141 65 -149 10 -20 39 -85 58 -131 8 -19 18 -42 23 +-51 4 -9 26 -61 49 -115 23 -54 53 -124 67 -154 45 -99 52 -115 58 -136 8 -29 +41 -58 58 -51 13 5 32 39 72 132 7 17 21 48 31 70 9 22 24 55 31 72 7 18 20 +49 28 68 8 19 22 51 30 70 8 19 21 50 29 68 18 44 40 95 59 137 31 72 48 111 +62 145 8 19 22 51 30 70 8 19 22 51 30 70 19 42 41 93 59 137 36 85 58 136 +105 241 17 37 31 73 31 80 0 7 4 17 9 22 5 6 26 51 46 100 21 50 48 113 60 +140 43 94 57 135 51 150 -8 21 -39 19 -53 -3z"/> +<path d="M6490 2282 c-73 -36 -78 -129 -9 -166 43 -23 80 -16 115 21 46 50 28 +115 -43 152 -27 14 -21 14 -63 -7z"/> +<path d="M5781 2266 c-8 -10 -13 -78 -14 -213 -1 -109 -6 -204 -10 -210 -6 -9 +-43 -13 -127 -13 -65 0 -125 -3 -134 -6 -19 -7 -21 -39 -3 -51 6 -4 71 -10 +142 -13 l130 -5 2 -215 c7 -644 7 -642 28 -680 74 -130 158 -197 277 -220 73 +-15 98 -10 98 19 0 25 -7 29 -77 42 -31 6 -74 19 -94 29 -42 22 -129 107 -129 +127 0 8 -7 24 -15 37 -13 20 -16 86 -18 442 l-2 419 131 3 c118 2 133 5 150 +23 18 20 18 21 -1 35 -14 10 -52 14 -146 14 l-127 0 -7 27 c-3 15 -5 112 -4 +216 2 155 0 190 -12 198 -19 12 -25 11 -38 -5z"/> +<path d="M2406 2214 c-27 -7 -54 -18 -60 -24 -5 -5 -15 -10 -22 -10 -25 0 +-152 -81 -211 -135 -66 -59 -146 -163 -183 -235 -12 -25 -29 -57 -36 -72 -8 +-14 -14 -36 -14 -48 0 -12 -5 -31 -11 -42 -9 -16 -7 -24 5 -36 24 -24 48 -5 +63 49 67 228 278 436 508 498 57 15 68 25 60 50 -7 24 -26 25 -99 5z"/> +<path d="M2778 2219 c-10 -5 -18 -16 -18 -22 0 -15 51 -47 74 -47 21 0 138 +-56 195 -93 53 -35 188 -168 202 -200 5 -12 18 -35 29 -52 11 -16 22 -37 26 +-45 3 -8 12 -30 20 -48 8 -18 14 -40 14 -48 0 -27 32 -84 46 -84 22 0 38 43 +25 68 -6 11 -11 28 -11 37 0 33 -91 202 -143 265 -29 35 -82 88 -117 117 -66 +53 -206 129 -263 143 -18 4 -39 10 -47 14 -8 3 -23 1 -32 -5z"/> +<path d="M2480 2099 c-41 -10 -86 -24 -100 -30 -14 -7 -41 -19 -60 -28 -99 +-45 -224 -168 -278 -271 -65 -125 -76 -171 -76 -325 -1 -119 3 -149 21 -200 +42 -118 56 -143 126 -229 156 -192 437 -288 662 -226 93 26 143 44 157 58 7 7 +18 12 24 12 17 0 134 89 174 132 44 48 107 155 137 234 23 62 26 83 27 214 1 +125 -2 153 -21 205 -68 189 -180 317 -349 400 -50 25 -99 45 -107 45 -9 0 -42 +7 -74 15 -74 19 -169 17 -263 -6z m278 -47 c9 -6 7 -14 -8 -30 -12 -12 -25 +-22 -31 -22 -15 0 -114 -75 -163 -123 -91 -90 -164 -214 -207 -353 -15 -48 +-24 -64 -38 -64 -27 0 -131 48 -137 63 -3 8 0 31 5 53 42 169 181 353 337 447 +55 33 65 35 144 36 47 0 91 -3 98 -7z m-388 -60 c0 -5 -10 -17 -21 -28 -70 +-62 -173 -228 -215 -347 -9 -26 -20 -50 -24 -52 -4 -2 -22 9 -41 25 -32 29 +-33 31 -20 68 30 89 73 155 151 231 73 71 170 130 170 103z m587 -24 c26 -17 +52 -35 57 -39 5 -5 -34 -28 -86 -52 -165 -77 -251 -176 -314 -363 -17 -49 -19 +-51 -68 -62 -29 -7 -75 -12 -104 -12 -51 0 -52 1 -52 30 0 52 82 222 145 303 +90 113 252 224 332 226 31 1 54 -7 90 -31z m148 -125 c30 -31 82 -118 103 +-173 31 -82 51 -210 42 -273 l-6 -42 -22 42 c-12 23 -22 51 -22 62 0 20 -14 +55 -53 136 -32 66 -42 83 -93 147 -84 105 -80 95 -42 112 48 21 62 19 93 -11z +m-169 -50 c56 -37 204 -266 204 -317 0 -7 7 -31 16 -52 12 -28 16 -72 17 -161 +0 -116 -1 -124 -27 -163 -27 -41 -73 -87 -83 -83 -2 2 -6 49 -9 104 -5 126 +-21 188 -84 319 -37 78 -75 133 -147 210 -24 25 -43 50 -43 56 0 13 33 44 84 +78 46 31 40 30 72 9z m-135 -198 c113 -129 170 -248 196 -410 11 -71 12 -106 +3 -164 -6 -41 -15 -80 -20 -86 -11 -13 -114 -65 -129 -65 -6 0 -11 63 -13 163 +l-3 162 -35 69 c-19 39 -58 95 -87 127 -60 64 -63 82 -33 159 43 110 59 116 +121 45z m-730 -71 c13 -14 33 -30 44 -35 11 -5 34 -18 50 -29 17 -11 37 -22 +45 -26 8 -3 30 -12 48 -20 44 -19 211 -28 292 -16 78 12 91 6 150 -71 40 -54 +49 -80 29 -92 -26 -16 -151 -36 -229 -36 -140 0 -276 36 -387 103 -95 57 -103 +69 -103 159 0 72 4 85 31 88 3 1 16 -11 30 -25z m-6 -253 c7 -13 137 -74 205 +-97 81 -28 373 -28 443 0 34 14 51 16 59 8 6 -6 11 -46 12 -89 l1 -78 -50 -17 +c-66 -23 -310 -24 -370 -3 -22 8 -47 15 -55 15 -22 0 -140 60 -182 92 -38 29 +-104 150 -93 169 8 12 22 12 30 0z m285 -326 c99 -25 275 -31 343 -11 81 24 +87 22 87 -22 0 -21 -7 -48 -16 -60 -14 -21 -23 -22 -132 -22 -81 0 -132 5 +-167 16 -76 25 -177 75 -205 102 l-25 25 25 -6 c14 -3 54 -13 90 -22z"/> +<path d="M5157 1843 c-4 -3 -7 -77 -7 -164 0 -87 -4 -160 -9 -163 -5 -3 -21 +13 -37 35 -98 142 -288 239 -465 239 -92 0 -234 -39 -280 -77 -8 -7 -21 -13 +-28 -13 -7 0 -47 -35 -89 -78 -78 -79 -124 -154 -156 -256 -22 -69 -21 -245 1 +-311 45 -137 104 -224 203 -299 80 -62 158 -95 265 -113 85 -14 101 -14 179 0 +144 27 273 103 358 211 22 28 44 52 49 54 5 2 9 -54 9 -125 0 -70 4 -134 9 +-141 5 -8 17 -12 27 -10 18 3 19 25 22 611 l2 607 -23 0 c-13 0 -27 -3 -30 -7z +m-381 -136 c174 -57 294 -174 354 -345 38 -106 23 -276 -34 -387 -44 -86 -138 +-177 -225 -220 -20 -9 -49 -23 -65 -31 -38 -19 -187 -28 -256 -16 -71 13 -113 +29 -176 69 -72 44 -90 60 -137 123 -76 100 -107 191 -107 310 0 120 31 209 +107 312 127 168 352 246 539 185z"/> +<path d="M6500 1801 c-6 -13 -10 -217 -10 -593 0 -607 1 -626 43 -596 17 13 +18 49 17 597 0 574 -2 611 -31 611 -5 0 -13 -9 -19 -19z"/> +<path d="M7875 1773 c-81 -25 -127 -45 -182 -81 -55 -35 -158 -140 -174 -176 +-5 -12 -13 -28 -17 -36 -26 -46 -35 -69 -53 -134 -24 -90 -24 -171 0 -266 59 +-237 242 -402 486 -439 66 -10 95 -10 165 3 131 22 212 61 297 139 84 77 31 +112 -55 36 -26 -22 -81 -57 -122 -77 -73 -34 -78 -35 -200 -36 -107 -1 -133 2 +-183 22 -78 30 -166 91 -216 149 -45 52 -101 157 -101 188 0 11 -4 27 -10 35 +-24 39 -8 40 533 40 483 0 521 1 533 18 18 23 17 85 -1 172 -46 220 -198 378 +-426 444 -70 20 -207 20 -274 -1z m249 -59 c55 -15 100 -34 170 -72 59 -31 +186 -183 186 -221 0 -5 6 -21 14 -36 21 -41 31 -151 16 -170 -11 -13 -78 -15 +-489 -15 -262 0 -486 3 -498 6 -12 3 -24 12 -27 19 -9 24 26 149 61 221 35 71 +121 169 174 199 139 79 270 102 393 69z"/> +<path d="M1595 1463 c-16 -16 -16 -18 5 -35 19 -15 41 -18 145 -18 106 0 124 +2 139 18 15 18 15 20 -2 35 -28 25 -263 25 -287 0z"/> +<path d="M3380 1464 c-11 -12 -10 -18 4 -32 14 -14 38 -17 146 -17 136 0 157 +6 145 44 -6 20 -13 21 -144 21 -113 0 -141 -3 -151 -16z"/> +<path d="M1875 1299 c-10 -14 4 -97 22 -139 55 -129 100 -197 183 -280 75 -75 +128 -112 235 -163 101 -49 185 -59 185 -23 0 14 -51 46 -74 46 -50 0 -220 105 +-301 185 -45 45 -117 143 -136 185 -37 80 -49 111 -49 126 0 45 -48 92 -65 63z"/> +<path d="M3346 1268 c-8 -13 -18 -36 -22 -53 -13 -57 -79 -177 -132 -241 -29 +-35 -85 -88 -125 -118 -72 -52 -193 -116 -222 -116 -21 0 -95 -38 -95 -49 0 +-5 7 -14 16 -22 49 -41 327 101 445 227 74 81 141 197 183 319 16 47 16 50 -1 +62 -23 18 -30 16 -47 -9z"/> +<path d="M2612 708 c-19 -19 -17 -272 3 -288 8 -7 22 -10 30 -6 23 8 18 299 +-5 304 -9 1 -21 -3 -28 -10z"/> +</g> +</svg> diff --git a/Interface/js/edit-players.js b/Interface/js/edit-players.js new file mode 100644 index 0000000000000000000000000000000000000000..7c4aaed5fd07c57848f8154eb96830fd42dbd36d --- /dev/null +++ b/Interface/js/edit-players.js @@ -0,0 +1,101 @@ +document.addEventListener('DOMContentLoaded', async function () { + try { + await loadKnownData(); + + if (playerId) { + document.getElementById('saveChanges').addEventListener('click', sendInfo); + + document.getElementById('cancelChanges').addEventListener('click', () => { + if (window.electron) { + window.electron.cancelPlayerInfoChanges(); + } else { + console.error("window.electron est indéfini !"); + } + }); + } else { + console.error("Aucun nom de joueuse trouvé dans l'URL !"); + } + } catch (error) { + console.error('Erreur lors du chargement des données:', error); + } +}); + +const urlParams = new URLSearchParams(window.location.search); +const playerId = urlParams.get('playerId'); + +async function loadKnownData(){ + const response = await fetch('data/infoPlayers.json'); + const infoplayers = await response.json(); + // Trouver la joueuse sélectionnée dans le JSON + const playerData = infoplayers.find(player => player.playerId === parseInt(playerId)); + const playerPhoto = document.getElementById('editPlayerPhoto'); + const photoPath = `data/photos/player${playerId}.jpg?v=${new Date().getTime()}`; + if (playerPhoto) { + playerPhoto.src = photoPath; + } + const fields = { + editPlayerHeight: 'taille', + editPlayerWeight: 'poids', + editPlayerAttack: 'attaque', + editPlayerBlockHeight: 'block', + }; + const fieldsValue = { + editPositionPlayed: 'position', + editPlayerBirthDate: 'birth', + }; + if (playerData) { + Object.entries(fields).forEach(([fieldId, jsonKey]) => { + const inputElement = document.getElementById(fieldId); + if (inputElement && playerData[jsonKey]) { + inputElement.placeholder = playerData[jsonKey]; + } + }); + Object.entries(fieldsValue).forEach(([fieldId, jsonKey]) => { + const inputElement = document.getElementById(fieldId); + if (inputElement && playerData[jsonKey]) { + inputElement.value = playerData[jsonKey]; + } + }); + document.getElementById("editPlayerComments").value = playerData['comments'] || ''; + document.getElementById("editPlayerName").value = playerData['playerName'] || ''; + } +} + +async function sendInfo(){ + if (window.electron) { + const fields = ['editPlayerHeight', 'editPlayerWeight', 'editPlayerAttack', 'editPlayerBlockHeight']; + // Mettre à jour les placeholders des inputs + fields.forEach(fieldId => { + const inputElement = document.getElementById(fieldId); + if (inputElement.value.trim() !== "") { + inputElement.placeholder = inputElement.value; + } + }); + const playerData = { + playerId : playerId, + playerName : document.getElementById('editPlayerName').value, + position: document.getElementById('editPositionPlayed').value, + birthDate: document.getElementById('editPlayerBirthDate').value, + height: document.getElementById('editPlayerHeight').value, + weight: document.getElementById('editPlayerWeight').value, + attack: document.getElementById('editPlayerAttack').value, + block: document.getElementById('editPlayerBlockHeight').value, + comments: document.getElementById('editPlayerComments').value + }; + console.log(playerData) + window.electron.savePlayerInfoChanges(playerData); + } else { + console.error("window.electron est indéfini !"); + } +} + + +document.getElementById('changePhoto').addEventListener('click', function() { + if (window.electron) { + window.electron.selectPlayerPhoto(playerId); + window.electron.onPhotoSelected((photoPath) => { + loadKnownData(); + }); + } +}); + diff --git a/Interface/js/loadPageElements.js b/Interface/js/loadPageElements.js new file mode 100644 index 0000000000000000000000000000000000000000..77f9601ddea0116e90d4bfeeab875981d934932f --- /dev/null +++ b/Interface/js/loadPageElements.js @@ -0,0 +1,142 @@ +// -------------------------------------------------------------------------------------------------Affichage du footer +// Il faut attendre que le menu soit load pour pouvoir détecter des clics dessus (rentrer/sortir menu + changer de page) +fetch('footer.html').then(response => response.text()).then(data => { + document.getElementById('footer').innerHTML = data; +}) +.catch(err => console.error('Erreur de chargement du menu:', err)); +// -------------------------------------------------------------------------------------------------Affichage du menu +function loadmenu() { +fetch(`menu.html?nocache=${new Date().getTime()}`, { +cache: 'no-store', +headers: { +'Cache-Control': 'no-cache, no-store, must-revalidate', +'Pragma': 'no-cache', +'Expires': '0' +} +}) +.then(response => response.text()) +.then(data => { +document.getElementById('menu').innerHTML = data; +configureMenuEvents(); +}) +.catch(err => console.error('Erreur de chargement du menu:', err)); +} +loadmenu(); +window.loadmenu = loadmenu; + +// -------------------------------------------------------------------------------------------------Affichage de la navigation +function loadnav() { + fetch(`nav.html?${new Date().getTime()}`) + .then(response => response.text()) + .then(data => { + document.getElementById('nav').innerHTML = data; + + // Faire en sorte que le menu rentre/sorte + const sidebarToggle = document.body.querySelector('#sidebarToggle'); + //console.log('sidebarToggle:', sidebarToggle); // Si c'est null, l'élément n'existe pas + if (sidebarToggle) { + sidebarToggle.addEventListener('click', event => { + try { + event.preventDefault(); + document.body.classList.toggle('sb-sidenav-toggled'); + sessionStorage.setItem('sb|sidebar-toggle', document.body.classList.contains('sb-sidenav-toggled')); + } catch (e) { + console.error('Erreur avec sessionStorage:', e); + } + }); + } else { + console.error('sidebarToggle n\'a pas été trouvé.'); + } + }) + .catch(err => console.error('Erreur de chargement du menu:', err)); +} +loadnav(); + + +// Extraire la configuration des événements du menu dans une fonction séparée +function configureMenuEvents() { + // Restaurer l'état du sous-menu "Joueuses" + const isJoueusesOpen = sessionStorage.getItem('joueusesMenuOpen') === 'true'; + const joueusesSubmenu = document.querySelector('#collapseLayouts'); + if (joueusesSubmenu) { + if (isJoueusesOpen) { + joueusesSubmenu.classList.add('show'); + } else { + joueusesSubmenu.classList.remove('show'); + } + } + + // Détecter retour à l'accueil + const accueilLink = document.getElementById('accueil'); + if (accueilLink) { + accueilLink.addEventListener('click', function (event) { + event.preventDefault(); + console.log('Accueil cliqué'); + sessionStorage.removeItem('selectedPlayerId'); + window.location.href = `index.html`; + }); + } + + // Détecter changement de page -> joueuse + const playerLinks = document.querySelectorAll('.nav-link[id^="player"]'); + fetch('data/infoPlayers.json?nocache=' + new Date().getTime(), { + cache: 'no-store', + headers: { + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0' + } + }) + .then(response => response.json()) + .then(infoPlayers => { + playerLinks.forEach(link => { + if (link) { + link.addEventListener('click', function (event) { + event.preventDefault(); + const playerId = event.target.id.replace('player', ''); + const playerData = infoPlayers.find(player => player.playerId == playerId); + + if (playerData) { + console.log(playerId + ' cliqué'); + sessionStorage.setItem('selectedPlayerId', playerId); + window.location.href = `tables.html`; + } else { + console.error('Joueur non trouvé pour l\'ID :', playerId); + } + }); + } + }); + }) + .catch(error => console.error('Erreur lors du chargement des joueurs:', error)); + + // Gestion du toggle du sous-menu + const joueusesToggle = document.querySelector('#joueusesToggle'); + if (joueusesToggle && joueusesSubmenu) { + joueusesToggle.addEventListener('click', function () { + const isOpen = joueusesSubmenu.classList.contains('show'); + sessionStorage.setItem('joueusesMenuOpen', !isOpen); + }); + } +} + +function addPlayer() { + if (window.electron) { + window.electron.showInputDialog(); + window.electron.receivePlayerName((playerId) => { + console.log("Update de menu demandée pour l'id :", playerId); + sessionStorage.setItem('selectedPlayerId', playerId) + window.electron.updateMenu(playerId); + window.electron.onMenuUpdated((event, addedPlayerId) => { + if (addedPlayerId === playerId) { + console.log(`Menu updated pour l'id ${playerId}`); + loadmenu(); + window.electron.redirectTo("tables.html"); + } + }); + + }); + } else { + console.error("window.electron est indéfini."); + } +} + diff --git a/Interface/js/mainTables.js b/Interface/js/mainTables.js new file mode 100644 index 0000000000000000000000000000000000000000..b64f15ea15776e91da53da5d40eea437e39410d3 --- /dev/null +++ b/Interface/js/mainTables.js @@ -0,0 +1,300 @@ +async function loadPlayerData(selectedPlayerId) { + const jsonFile = `data/player${selectedPlayerId}/data${selectedPlayerId}.json`; + try { + // ---------------------------------------------------------------- Charge les infos : taille, poids... + const response = await fetch('data/infoPlayers.json'); + const players = await response.json(); + + const playerPhoto = document.getElementById('playerPhoto'); + const defaultPhotoPath = 'icons/default-avatar.jpg'; + const basePhotoPath = `data/player${selectedPlayerId}/player${selectedPlayerId}.jpg`; + const photoPath = `${basePhotoPath}?v=${new Date().getTime()}`; + const tempImg = new Image(); + playerPhoto.src = defaultPhotoPath; + tempImg.onload = function() { + playerPhoto.src = photoPath; + }; + tempImg.onerror = function() { + console.log("Pas de photo pour la joueuse ", selectedPlayerId) + }; + tempImg.src = basePhotoPath; + + const playerData = players.find(player => player.playerId == selectedPlayerId); + function formaterDate(dateStr) { + const moisAbreges = ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.']; + const date = new Date(dateStr); + const jour = date.getDate(); // Jour du mois (1-31) + const mois = moisAbreges[date.getMonth()]; // Mois abrégé + const annee = date.getFullYear(); // Année (aaaa) + return `${jour} ${mois} ${annee}`; + } + if (playerData) { + document.getElementById('playerName').textContent = playerData.playerName ?? '...'; + document.getElementById('positionPlayed').textContent = playerData.position ?? '...'; + document.getElementById('playerBirthDate').textContent = (playerData.birth !== null) ? formaterDate(playerData.birth) : '...'; document.getElementById('playerHeight').textContent = playerData.taille ?? '...'; + document.getElementById('playerWeight').textContent = playerData.poids ?? '...'; + document.getElementById('playerAttack').textContent = playerData.attaque ?? '...'; + document.getElementById('playerBlockHeight').textContent = playerData.block ?? '...'; + document.getElementById('playerComments').textContent = playerData.comments ?? 'Commentaires sur la joueuse...'; + } else { + console.log(`Joueuse avec l'id "${selectedPlayerId}" introuvable dans le fichier JSON.`); + } + + // ---------------------------------------------------------------- Charge les infos de performance + const perfData = await fetch(jsonFile); + const data = await perfData.json(); + + // ✅ Attendre que la table soit remplie avant d'initialiser le DataTable + await fillTable(data); + + const datatablesSimple = document.getElementById('datatablesSimple'); + if (typeof simpleDatatables !== 'undefined' && simpleDatatables.DataTable) { + if (datatablesSimple) { + // Vérifie si une instance existe déjà et la détruit + if (dataTableInstance) { + dataTableInstance.destroy(); + } + + // ✅ Initialiser simpleDatatables après le remplissage + dataTableInstance = new simpleDatatables.DataTable(datatablesSimple, { + labels: { + placeholder: "Rechercher...", + perPage: "entrées par page", + noRows: "Aucune entrée trouvée", + info: "Affichage de {start} à {end} sur {rows} entrées", + }, + }); + } else { + console.error("⌠Élément 'datatablesSimple' introuvable"); + } + } else { + console.error("⌠simpleDatatables non défini !"); + } + } catch (error) { + console.error('Erreur lors du chargement des données:', error); + } +} + + +function createVideoThumbnail(videoUrl) { + return new Promise((resolve, reject) => { + // Log de débogage + console.log("URL de la vidéo:", videoUrl); + + if (!videoUrl) { + console.error("URL de vidéo vide"); + reject(new Error("URL de vidéo vide")); + return; + } + + const video = document.createElement('video'); + video.crossOrigin = 'Anonymous'; + video.preload = 'metadata'; + + // Log des erreurs détaillées + video.onerror = (err) => { + console.error("Erreur de chargement vidéo:", err); + console.error("Détails de l'erreur:", { + error: err, + src: video.src, + networkState: video.networkState, + readyState: video.readyState + }); + reject(err); + }; + + // Essayez différents types de chemins + try { + // Si c'est un chemin relatif, préfixez avec le chemin de base + video.src = videoUrl.startsWith('http') + ? videoUrl + : `${window.location.origin}/${videoUrl.replace(/^\//, '')}`; + } catch (err) { + console.error("Erreur lors de l'assignation de l'URL:", err); + reject(err); + } + + video.addEventListener('loadedmetadata', () => { + try { + const canvas = document.createElement('canvas'); + canvas.width = video.videoWidth; + canvas.height = video.videoHeight; + + const ctx = canvas.getContext('2d'); + ctx.drawImage(video, 0, 0, canvas.width, canvas.height); + + const thumbnailDataUrl = canvas.toDataURL('image/jpeg'); + resolve(thumbnailDataUrl); + } catch (err) { + console.error("Erreur lors de la création de la miniature:", err); + reject(err); + } + }); + }); +} + +function createVideoCell(videoUrl) { + const vidCell = document.createElement("td"); + + if (!videoUrl) { + vidCell.textContent = "Pas de vidéo"; + return vidCell; + } + + const thumbnailContainer = document.createElement("div"); + thumbnailContainer.classList.add("video-thumbnail-container"); + + const thumbnailImg = document.createElement("img"); + thumbnailImg.classList.add("video-thumbnail"); + + const playOverlay = document.createElement("div"); + playOverlay.classList.add("video-play-overlay"); + + createVideoThumbnail(videoUrl) + .then(thumbnailSrc => { + thumbnailImg.src = thumbnailSrc; + }) + .catch(() => { + // Gérer les erreurs de thumbnail + thumbnailImg.src = `data:image/svg+xml;base64,${btoa(` + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 60" width="100" height="60"> + <rect width="100" height="60" fill="#e0e0e0"/> + <text x="50" y="30" font-family="Arial, sans-serif" font-size="10" + text-anchor="middle" alignment-baseline="middle" fill="#666"> + Erreur thumbnail + </text> + </svg> + `)}`; + }); + + thumbnailContainer.appendChild(thumbnailImg); + thumbnailContainer.appendChild(playOverlay); + + thumbnailContainer.onclick = () => { + window.open(videoUrl, '_blank', + 'width=800,height=600,resizable=yes,scrollbars=yes'); + }; + + vidCell.appendChild(thumbnailContainer); + + console.log("vidcell : ", vidCell) + + return vidCell; +} + +async function fillTable(data) { + return new Promise((resolve) => { + const table = document.getElementById("datatablesSimple"); + const tableHead = table.querySelector("thead"); + const tableFoot = table.querySelector("tfoot"); + const tableBody = table.querySelector("tbody"); + + // On vide la table avant de la remplir + tableBody.innerHTML = ""; + + if (!data || Object.keys(data).length === 0) { + console.log("Aucune donnée disponible"); + tableHead.innerHTML = ""; + tableFoot.innerHTML = ""; + if (dataTableInstance) { + dataTableInstance.destroy(); + dataTableInstance = null; + + dataTableInstance = new simpleDatatables.DataTable(table, { + labels: { + placeholder: "Rechercher...", + perPage: "entrées par page", + noRows: "Aucune entrée trouvée", + info: "Affichage de {start} à {end} sur {rows} entrées", + }, + data: { // Ajouter une table vide + headings: ["Date", "Heure", "Performance", "Vidéo", "Durée", "Actions"], + data: [] + } + }); + } + return resolve(); + } + + data.forEach(entry => { + const row = document.createElement("tr"); + row.classList.add("text-red"); + //console.log("rang créé avec classList", row.classList, "et data-session-id =", row.dataset.sessionId); + + // Colonne de la date + const dateCell = document.createElement("td"); + dateCell.textContent = entry.date; + dateCell.classList.add("datecell"); + row.appendChild(dateCell); + + // Colonne de l'heure + const hourCell = document.createElement("td"); + hourCell.textContent = entry.heure; + row.appendChild(hourCell); + + // Colonne de la performance + const performanceCell = document.createElement("td"); + + const percentageBarContainer = document.createElement("div"); + percentageBarContainer.classList.add("percentage-bar-container"); + + const percentageBar = document.createElement("div"); + percentageBar.classList.add("percentage-bar"); + + entry.performance.forEach(segment => { + if (!segment.color || !segment.percentage) { + console.error('Segment invalide:', segment); + return; + } + const segmentDiv = document.createElement("div"); + segmentDiv.classList.add("bar-section", segment.color); + segmentDiv.style.width = `${segment.percentage}%`; + percentageBar.appendChild(segmentDiv); + }); + + percentageBarContainer.appendChild(percentageBar); + performanceCell.appendChild(percentageBarContainer); + row.appendChild(performanceCell); + + // Colonne de la vidéo + const vidCell = createVideoCell(entry.id); + row.appendChild(vidCell); + + // Colonne de la durée de la vidéo + const durationCell = document.createElement("td"); + durationCell.textContent = entry.video_duration; + row.appendChild(durationCell); + + // Colonne de suppression avec l'icône de la poubelle + const deleteCell = document.createElement("td"); + deleteCell.classList.add("delete-cell"); + const deleteButton = document.createElement("img"); + deleteButton.src = "icons/poubelle.png"; + deleteButton.alt = "Poubelle"; + deleteButton.classList.add("delete-button"); + + deleteCell.appendChild(deleteButton); + row.appendChild(deleteCell); + + tableBody.appendChild(row) + }); + + resolve(); // Une fois toutes les lignes ajoutées, on résout la promesse + }); +} + +async function main() { + selectedPlayerId = sessionStorage.getItem('selectedPlayerId'); + //console.log("selectedPlayer récupéré:", selectedPlayer); + if (selectedPlayerId !== null && selectedPlayerId !== 'null') { + //console.log("Chargement des données pour:", selectedPlayer); + await loadPlayerData(selectedPlayerId); + } else { + console.log("Aucun joueur sélectionné, chargement annulé."); + } +} +window.main = main; + +document.addEventListener('DOMContentLoaded', function () { + main(); +}); \ No newline at end of file diff --git a/Interface/js/scripts.js b/Interface/js/scripts.js index b6c58a846aed8d47422ca25ce680e51e2e077535..c2d3045ce02d19dfe8b82b95fdc114f849317a4e 100644 --- a/Interface/js/scripts.js +++ b/Interface/js/scripts.js @@ -10,64 +10,26 @@ document.addEventListener('DOMContentLoaded', () => { }); }); -// Afficher le menu et le footer +// -------------------------------------------------------------------------------------------------Affichage du footer // Il faut attendre que le menu soit load pour pouvoir détecter des clics dessus (rentrer/sortir menu + changer de page) fetch('footer.html').then(response => response.text()).then(data => { document.getElementById('footer').innerHTML = data; }) .catch(err => console.error('Erreur de chargement du menu:', err)); - +// -------------------------------------------------------------------------------------------------Affichage du menu function loadmenu() { - fetch(`menu.html?${new Date().getTime()}`) + fetch(`menu.html?nocache=${new Date().getTime()}`, { + cache: 'no-store', + headers: { + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0' + } + }) .then(response => response.text()) .then(data => { document.getElementById('menu').innerHTML = data; - - // Restaurer l'état du sous-menu "Joueuses" - const isJoueusesOpen = localStorage.getItem('joueusesMenuOpen') === 'true'; - const joueusesSubmenu = document.querySelector('#collapseLayouts'); // Sélectionnez le sous-menu "Joueuses" - if (joueusesSubmenu) { - if (isJoueusesOpen) { - joueusesSubmenu.classList.add('show'); // Ouvrir le sous-menu - } else { - joueusesSubmenu.classList.remove('show'); // Fermer le sous-menu - } - } - // Détecter retour à l'accueil - const accueilLink = document.getElementById('accueil'); - if (accueilLink) { - accueilLink.addEventListener('click', function (event) { - event.preventDefault(); // Empêche le rechargement de la page si nécessaire - console.log('Accueil cliqué'); - localStorage.setItem('selectedPlayer', null); - window.location.href = `index.html`; - selectedPlayer = null; - }); - } else { - console.error('Élément avec l\'id "accueil" introuvable'); - } - - // Savoir quelle joueuse on a cliqué - const playerLinks = document.querySelectorAll('[id^="player"]'); - playerLinks.forEach(link => { - if (link) { - link.addEventListener('click', function (event) { - event.preventDefault(); - const playerName = event.target.textContent.trim(); - console.log(playerName + ' cliquée'); - localStorage.setItem('selectedPlayer', playerName); - - window.location.href = `tables.html`; - }); - } - }); - const joueusesToggle = document.querySelector('#joueusesToggle'); // Bouton pour ouvrir/fermer le sous-menu - if (joueusesToggle) { - joueusesToggle.addEventListener('click', function () { - const isOpen = joueusesSubmenu.classList.contains('show'); - localStorage.setItem('joueusesMenuOpen', !isOpen); // Inverser l'état - }); - } + configureMenuEvents(); }) .catch(err => console.error('Erreur de chargement du menu:', err)); } @@ -87,9 +49,9 @@ function loadnav() { try { event.preventDefault(); document.body.classList.toggle('sb-sidenav-toggled'); - localStorage.setItem('sb|sidebar-toggle', document.body.classList.contains('sb-sidenav-toggled')); + sessionStorage.setItem('sb|sidebar-toggle', document.body.classList.contains('sb-sidenav-toggled')); } catch (e) { - console.error('Erreur avec localStorage:', e); + console.error('Erreur avec sessionStorage:', e); } }); } else { @@ -100,11 +62,50 @@ function loadnav() { } loadnav(); -async function loadPlayerData(selectedPlayer) { - const jsonFile = `data/data${selectedPlayer}.json`; +async function loadPlayerData(selectedPlayerId) { + const jsonFile = `data/data${selectedPlayerId}.json`; try { - const response = await fetch(jsonFile); - const data = await response.json(); + // ---------------------------------------------------------------- Charge les infos : taille, poids... + const response = await fetch('data/infoPlayers.json'); + const players = await response.json(); + + const playerPhoto = document.getElementById('playerPhoto'); + const basePhotoPath = `data/photos/player${selectedPlayerId}.jpg`; + const photoPath = `${basePhotoPath}?v=${new Date().getTime()}`; + const tempImg = new Image(); + tempImg.onload = function() { + playerPhoto.src = photoPath; + }; + tempImg.onerror = function() { + console.log("Pas de photo pour la joueuse ", selectedPlayerId) + }; + tempImg.src = basePhotoPath; // Essayer de charger l'image sans le paramètre de version + + const playerData = players.find(player => player.playerId == selectedPlayerId); + function formaterDate(dateStr) { + const moisAbreges = ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.']; + const date = new Date(dateStr); + const jour = date.getDate(); // Jour du mois (1-31) + const mois = moisAbreges[date.getMonth()]; // Mois abrégé + const annee = date.getFullYear(); // Année (aaaa) + return `${jour} ${mois} ${annee}`; + } + if (playerData) { + document.getElementById('playerName').textContent = playerData.playerName ?? '...'; + document.getElementById('positionPlayed').textContent = playerData.position ?? '...'; + if (playerData.birth !== null){document.getElementById('playerBirthDate').textContent = formaterDate(playerData.birth) ?? '...';} + document.getElementById('playerHeight').textContent = playerData.taille ?? '...'; + document.getElementById('playerWeight').textContent = playerData.poids ?? '...'; + document.getElementById('playerAttack').textContent = playerData.attaque ?? '...'; + document.getElementById('playerBlockHeight').textContent = playerData.block ?? '...'; + document.getElementById('playerComments').textContent = playerData.comments ?? 'Commentaires sur la joueuse...'; + } else { + console.error(`Joueuse "${selectedPlayer}" introuvable dans le fichier JSON.`); + } + + // ---------------------------------------------------------------- Charge les infos de performance + const perfData = await fetch(jsonFile); + const data = await perfData.json(); // ✅ Attendre que la table soit remplie avant d'initialiser le DataTable await fillTable(data); @@ -230,17 +231,20 @@ document.addEventListener('click', function(event) { }); async function main() { - selectedPlayer = localStorage.getItem('selectedPlayer'); - console.log("selectedPlayer récupéré:", selectedPlayer); - - if (selectedPlayer !== null && selectedPlayer !== 'null') { - console.log("Chargement des données pour:", selectedPlayer); - await loadPlayerData(selectedPlayer); + selectedPlayerId = sessionStorage.getItem('selectedPlayerId'); + //console.log("selectedPlayer récupéré:", selectedPlayer); + if (selectedPlayerId !== null && selectedPlayerId !== 'null') { + //console.log("Chargement des données pour:", selectedPlayer); + await loadPlayerData(selectedPlayerId); } else { console.log("Aucun joueur sélectionné, chargement annulé."); } } +document.addEventListener('DOMContentLoaded', function () { + main(); +}); + // Fonction pour supprimer une ligne de statistiques function deleteRow(button) { @@ -261,16 +265,16 @@ function deleteRow(button) { // Appeler la méthode exposée dans le processus de rendu via preload.js if (window.electron) { - playerName=localStorage.getItem('selectedPlayer'); - console.log("Suppression demandée pour :", playerName, date); - window.electron.deleteR(playerName, date); + playerId = sessionStorage.getItem('selectedPlayerId'); + console.log("Suppression demandée pour :", playerId, date, hour); + window.electron.deleteR(playerId, date, hour); } else { console.error("window.electron est indéfini."); } - window.electron.onRowDeleted((event, deletedDate, deletedPlayerName) => { - if (deletedDate === date && deletedPlayerName === playerName) { - console.log(`Ligne avec la date ${date} supprimée avec succès pour ${playerName}`); + window.electron.onRowDeleted((event, deletedPlayerId, deletedDate, deletedHour) => { + if (deletedDate === date && deletedPlayerId === playerId) { + console.log(`Ligne avec la date ${date} supprimée avec succès pour l'id ${playerId}`); // Sauvegarde du nombre d'entrées par page let entriesPerPage = dataTableInstance ? dataTableInstance.options.perPage : 10; @@ -303,13 +307,13 @@ function deleteRow(button) { function addPlayer() { if (window.electron) { window.electron.showInputDialog(); - window.electron.receivePlayerName((playerName) => { - console.log("Update de menu demandée pour :", playerName); - window.electron.updateMenu(playerName); + window.electron.receivePlayerName((playerId) => { + console.log("Update de menu demandée pour l'id :", playerId); + window.electron.updateMenu(playerId); - window.electron.onMenuUpdated((event, addedPlayerName) => { - if (addedPlayerName === playerName) { - console.log(`Menu updated pour ${playerName}`); + window.electron.onMenuUpdated((event, addedPlayerId) => { + if (addedPlayerId === playerId) { + console.log(`Menu updated pour l'id ${playerId}`); loadmenu(); } }); @@ -320,6 +324,108 @@ function addPlayer() { } } -document.addEventListener('DOMContentLoaded', function () { - main(); + +document.getElementById('editPlayer').addEventListener('click', function() { + if (window.electron) { + const playerId = sessionStorage.getItem('selectedPlayerId'); + window.electron.updatePlayerInfo(playerId); + window.electron.onPlayerInfoUpdated((playerData) => { + if (parseInt(playerData.playerId) == sessionStorage.getItem('selectedPlayerId')) { + //console.log(`Infos mises à jour dans le JSON et le menu pour l'id ${playerData.playerId} et le nom ${playerData.playerName}`); + // Force le rechargement complet du menu avec un timeout pour s'assurer que le fichier est bien mis à jour + setTimeout(() => { + // Vider d'abord le contenu du menu + document.getElementById('menu').innerHTML = ''; + // Puis recharger avec un timestamp unique pour éviter le cache + fetch(`menu.html?nocache=${new Date().getTime()}`, { + cache: 'no-store', + headers: { + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0' + } + }) + .then(response => response.text()) + .then(data => { + document.getElementById('menu').innerHTML = data; + // Reconfigurer tous les événements du menu + configureMenuEvents(); + // Puis recharger les données du joueur + main(); + }) + .catch(err => { + console.error('Erreur de rechargement du menu:', err); + // Tenter de recharger une seconde fois en cas d'échec + setTimeout(loadmenu, 500); + }); + }, 300); // Attendre 300ms pour s'assurer que le fichier est mis à jour + } + }); + } }); + +// Extraire la configuration des événements du menu dans une fonction séparée +function configureMenuEvents() { + // Restaurer l'état du sous-menu "Joueuses" + const isJoueusesOpen = sessionStorage.getItem('joueusesMenuOpen') === 'true'; + const joueusesSubmenu = document.querySelector('#collapseLayouts'); + if (joueusesSubmenu) { + if (isJoueusesOpen) { + joueusesSubmenu.classList.add('show'); + } else { + joueusesSubmenu.classList.remove('show'); + } + } + + // Détecter retour à l'accueil + const accueilLink = document.getElementById('accueil'); + if (accueilLink) { + accueilLink.addEventListener('click', function (event) { + event.preventDefault(); + console.log('Accueil cliqué'); + sessionStorage.removeItem('selectedPlayerId'); + window.location.href = `index.html`; + }); + } + + // Détecter changement de page -> joueuse + const playerLinks = document.querySelectorAll('.nav-link[id^="player"]'); + fetch('data/infoPlayers.json?nocache=' + new Date().getTime(), { + cache: 'no-store', + headers: { + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0' + } + }) + .then(response => response.json()) + .then(infoPlayers => { + playerLinks.forEach(link => { + if (link) { + link.addEventListener('click', function (event) { + event.preventDefault(); + const playerId = event.target.id.replace('player', ''); + const playerData = infoPlayers.find(player => player.playerId == playerId); + + if (playerData) { + console.log(playerId + ' cliqué'); + sessionStorage.setItem('selectedPlayerId', playerId); + window.location.href = `tables.html`; + } else { + console.error('Joueur non trouvé pour l\'ID :', playerId); + } + }); + } + }); + }) + .catch(error => console.error('Erreur lors du chargement des joueurs:', error)); + + // Gestion du toggle du sous-menu + const joueusesToggle = document.querySelector('#joueusesToggle'); + if (joueusesToggle && joueusesSubmenu) { + joueusesToggle.addEventListener('click', function () { + const isOpen = joueusesSubmenu.classList.contains('show'); + sessionStorage.setItem('joueusesMenuOpen', !isOpen); + }); + } +} diff --git a/Interface/js/scriptsTables.js b/Interface/js/scriptsTables.js new file mode 100644 index 0000000000000000000000000000000000000000..0bdf8020102fca51ba9eccaea86f3f7feb08664d --- /dev/null +++ b/Interface/js/scriptsTables.js @@ -0,0 +1,137 @@ +let selectedPlayer = null; +let dataTableInstance = null; + +document.addEventListener('click', function(event) { + if (event.target.classList.contains('delete-button')) { + console.log('Poubelle cliquée via addEventListener'); + deleteRow(event.target); + } +}); + +// Fonction pour récupérer le sessionId à partir de l'index de la ligne +async function fetchSessionIdFromIndex(playerId, dataIndex) { + try { + // Charger les données du joueur + const response = await fetch(`data/player${playerId}/data${playerId}.json`); + const data = await response.json(); + + // Vérifier si l'index est valide + if (dataIndex >= 0 && dataIndex < data.length) { + // Récupérer l'ID de session à partir des données originales + return data[dataIndex].id.toString(); + } + return null; + } catch (error) { + console.error("Erreur lors du chargement des données pour l'index:", error); + return null; + } +} + +// Fonction modifiée pour supprimer une ligne de statistiques +function deleteRow(button) { + const isConfirmed = confirm("Supprimer la ligne ?"); + + if (isConfirmed) { + // Récupérer la ligne avec closest + const row = button.closest('tr'); + + // Récupérer l'index de la ligne dans DataTables + const dataIndex = row.getAttribute('data-index'); + + // Vérifier si l'index existe + if (dataIndex === null) { + console.error("Impossible de trouver l'index de données dans la ligne"); + return; + } + + const playerId = sessionStorage.getItem('selectedPlayerId'); + console.log("dataIndex : ", dataIndex,", playerId :", playerId) + fetchSessionIdFromIndex(playerId, parseInt(dataIndex)) + .then(sessionId => { + if (!sessionId) { + console.error("Impossible de trouver le sessionId pour l'index", dataIndex); + return; + } + + // Appeler la méthode exposée dans le processus de rendu + if (window.electron) { + console.log("Suppression demandée pour le joueur", playerId, "et la session", sessionId); + window.electron.deleteR(playerId, sessionId); + } else { + console.error("window.electron est indéfini."); + } + + window.electron.onRowDeleted((event, deletedPlayerId, deletedSessionId) => { + if (deletedSessionId === sessionId && deletedPlayerId === playerId) { + console.log(`Ligne avec l'id ${sessionId} supprimée avec succès pour le joueur d'id ${playerId}`); + + // Sauvegarde du nombre d'entrées par page + let entriesPerPage = dataTableInstance ? dataTableInstance.options.perPage : 10; + + // Détruire l'instance DataTable + if (dataTableInstance) { + dataTableInstance.destroy(); + dataTableInstance = null; + } + + // Recharger les données et recréer le tableau + main().then(() => { + console.log("Table mise à jour après suppression."); + + // Restaurer le nombre d'entrées par page + if (dataTableInstance) { + dataTableInstance.options.perPage = entriesPerPage; + dataTableInstance.update(); + } + }); + } + }); + }) + .catch(error => { + console.error("Erreur lors de la récupération du sessionId:", error); + }); + } else { + console.log("Suppression annulée."); + } +} + +document.getElementById('editPlayer').addEventListener('click', function() { + if (window.electron) { + const playerId = sessionStorage.getItem('selectedPlayerId'); + window.electron.updatePlayerInfo(playerId); + window.electron.onPlayerInfoUpdated((playerData) => { + if (parseInt(playerData.playerId) == sessionStorage.getItem('selectedPlayerId')) { + //console.log(`Infos mises à jour dans le JSON et le menu pour l'id ${playerData.playerId} et le nom ${playerData.playerName}`); + // Force le rechargement complet du menu avec un timeout pour s'assurer que le fichier est bien mis à jour + setTimeout(() => { + // Vider d'abord le contenu du menu + document.getElementById('menu').innerHTML = ''; + // Puis recharger avec un timestamp unique pour éviter le cache + fetch(`menu.html?nocache=${new Date().getTime()}`, { + cache: 'no-store', + headers: { + 'Cache-Control': 'no-cache, no-store, must-revalidate', + 'Pragma': 'no-cache', + 'Expires': '0' + } + }) + .then(response => response.text()) + .then(data => { + document.getElementById('menu').innerHTML = data; + // Reconfigurer tous les événements du menu + configureMenuEvents(); + // Puis recharger les données du joueur + main(); + }) + .catch(err => { + console.error('Erreur de rechargement du menu:', err); + // Tenter de recharger une seconde fois en cas d'échec + setTimeout(loadmenu, 500); + }); + }, 300); // Attendre 300ms pour s'assurer que le fichier est mis à jour + } + }); + } +}); + + diff --git a/Interface/main.js b/Interface/main.js index d8aac92c9b3f48e5a5419a8fd6191fc3f96ec72c..c03d1a60aec520794ac0e15001807fa94cce83d4 100644 --- a/Interface/main.js +++ b/Interface/main.js @@ -50,9 +50,9 @@ ipcMain.on('ipc-example', (event, arg) => { }); // Écoute des demandes de suppression d'une ligne -ipcMain.on('delete-row', (event, playerName, date) => { +ipcMain.on('delete-row', (event, playerId, date, hour) => { // Construire le chemin du fichier en fonction de la joueuse sélectionnée - const filePath = path.join(__dirname, `data/data${playerName}.json`); + const filePath = path.join(__dirname, `data/data${playerId}.json`); // Lire le fichier JSON de la joueuse sélectionnée fs.readFile(filePath, 'utf8', (err, data) => { if (err) { @@ -69,7 +69,7 @@ ipcMain.on('delete-row', (event, playerName, date) => { console.error("Erreur lors de l'écriture du fichier JSON:", err); } else { //console.log(`Données mises à jour avec succès pour ${playerName}`); - event.reply('row-deleted', date, playerName); // Répondre pour confirmer la suppression + event.reply('row-deleted', playerId, date, hour); // Répondre pour confirmer la suppression } }); }); @@ -104,19 +104,32 @@ ipcMain.on("show-input-dialog", async (event) => { inputWindow.loadFile("input.html"); // Charge la page HTML pour entrer le prénom }); + ipcMain.on("submit-player-name", (event, playerName) => { - console.log if (!playerName) return; - let fileName = playerName.trim().toLowerCase(); - fileName = fileName.charAt(0).toUpperCase() + fileName.slice(1); - - let filePathJson = path.join(__dirname, "data", `data${fileName}.json`); - if (!fs.existsSync(path.join(__dirname, "data"))) { fs.mkdirSync(path.join(__dirname, "data")); } + // -------------------------------------------------------------------- Créer un json pour la joueuse + let infoPlayersPath = path.join(__dirname, "data", "infoPlayers.json"); + + // Charger les joueurs existants + let players = []; + if (fs.existsSync(infoPlayersPath)) { + players = JSON.parse(fs.readFileSync(infoPlayersPath, "utf-8")); + } + + // Trouver le prochain ID libre + let nextId = players.length > 0 ? Math.max(...players.map(p => p.playerId)) + 1 : 1; + + // Création du fichier JSON sous la forme dataId.json + let fileName = `data${nextId}.json`; + let filePathJson = path.join(__dirname, "data", fileName); + + + // Créer un fichier dataId.json fs.writeFile(filePathJson, "[]", (err) => { if (err) { console.error("Erreur lors de la création du fichier JSON :", err); @@ -124,15 +137,51 @@ ipcMain.on("submit-player-name", (event, playerName) => { console.log(`Fichier JSON vide créé : ${filePathJson}`); } }); + + // -------------------------------------------------------------------- Ajouter la joueuse à infoPlayers.json + + // Créer un nouvel objet joueur + let newPlayer = { + playerId: nextId, + playerName: playerName.trim(), + position: null, + birth: null, + taille: null, + poids: null, + attaque: null, + block: null, + comments: "" + }; + // Ajouter le nouveau joueur à infoPlayers.json + players.push(newPlayer); + fs.writeFileSync(infoPlayersPath, JSON.stringify(players, null, 2), (err) => { + if (err) { + console.error("Erreur lors de l'ajout de la joueuse à infoPlayers.json' :", err); + } else { + console.log(`Joueuse ajoutée à infoPlayers.json :`); + } + }); - mainWindow.webContents.send("player-name-received", playerName); // Envoie au renderer + mainWindow.webContents.send("player-name-received", nextId); // Envoie au renderer if (inputWindow && !inputWindow.isDestroyed()) { inputWindow.destroy(); // Ferme la fenêtre après validation } }); -ipcMain.on('update-menu', (event, playerName) => { +// Fonction pour retrouver un nom par ID +function getPlayerNameById(playerId) { + const infoPlayersPath = path.join(__dirname, "data", "infoPlayers.json"); + if (fs.existsSync(infoPlayersPath)) { + const players = JSON.parse(fs.readFileSync(infoPlayersPath, "utf-8")); + const player = players.find(p => p.playerId == playerId); + return player ? player.playerName : "Joueur non trouvé"; + } else { + console.log("Le fichier infoPlayers.json n'existe pas."); + } +} + +ipcMain.on('update-menu', (event, playerId) => { const menuPath = 'menu.html'; // Lire le fichier menu @@ -151,17 +200,135 @@ ipcMain.on('update-menu', (event, playerName) => { return; } + playerName = getPlayerNameById(playerId) // Créer le nouvel élément <a> - const newPlayer = `<a class="nav-link" href="tables.html" id="player${playerName}">${playerName}</a>`; + const newPlayer = `<a class="nav-link" href="tables.html" id="player${playerId}">${playerName}</a>`; $('#addPlayer').before(newPlayer); // Écrire le HTML mis à jour try { fs.writeFileSync(menuPath, $.html()); //console.log(`Menu mis à jour avec succès pour ${playerName}`); - event.reply('menu-updated', playerName); + event.reply('menu-updated', playerId); } catch (err) { console.error("Erreur lors de l'écriture du fichier html :", err); } }); }); + +ipcMain.on('update-player-info', (event, playerId) => { + // Étape 1: Ouvrir la fenêtre modale pour modifier les infos + inputWindow = new BrowserWindow({ + width: 800, + height: 820, + parent: mainWindow, // Spécifie la fenêtre principale comme parent + modal: true, // La fenêtre est modale, c'est-à -dire qu'on ne peut pas interagir avec la fenêtre principale tant que cette fenêtre est ouverte + //resizable: false, + webPreferences: { + preload: path.join(__dirname, 'preload.js'), + nodeIntegration: true // Permet d'utiliser `nodeIntegration` pour gérer les événements IPC + } + }); + inputWindow.webContents.openDevTools(); + inputWindow.loadURL(`file://${__dirname}/edit-player.html?playerId=${encodeURIComponent(playerId)}`); +}); + + +ipcMain.on('save-player-info', (event, playerData) => { + const playersFilePath = path.join(__dirname, 'data/infoPlayers.json'); + try { + let players = JSON.parse(fs.readFileSync(playersFilePath, 'utf8')); + // Trouver la joueuse correspondante + let playerIndex = players.findIndex(player => player.playerId === parseInt(playerData.playerId)); + if (playerIndex !== -1) { + let updatedPlayer = { ...players[playerIndex] }; + // Met à jour seulement si la valeur n'est pas null ou undefined + if (playerData.playerName !== ""){updatedPlayer.playerName = playerData.playerName;} + if (playerData.position !== "Choisir une position") {updatedPlayer.position = playerData.position;} + if (playerData.birthDate !== "") {updatedPlayer.birth = playerData.birthDate;} + if (playerData.height !== "") {updatedPlayer.taille = parseInt(playerData.height, 10);} + if (playerData.weight !== "") {updatedPlayer.poids = parseInt(playerData.weight, 10);} + if (playerData.attack !== "") {updatedPlayer.attaque = parseInt(playerData.attack, 10);} + if (playerData.block !== "") {updatedPlayer.block = parseInt(playerData.block, 10);} + updatedPlayer.comments = playerData.comments; + players[playerIndex] = updatedPlayer; + + // Sauvegarder les modifications dans le fichier JSON + fs.writeFileSync(playersFilePath, JSON.stringify(players, null, 4), 'utf8'); + + console.log(`✅ Données mises à jour dans le JSON pour l'id${playerData.playerId}`); + // -------------------------------------------------------------------------- Changer le menu + const menuPath = 'menu.html'; + fs.readFile(menuPath, 'utf8', (err, data) => { + if (err) { + console.error("Erreur lors de la lecture du fichier HTML:", err); + return; + } + + const $ = cheerio.load(data); + const playerElement = $(`.sb-sidenav-menu-nested a#player${playerData.playerId}`); + + if (playerElement.length) { + playerElement.text(playerData.playerName); // Mettre à jour le texte + try { + fs.writeFileSync(menuPath, $.html()); + console.log(`✅ Données mises à jour dans le menu pour ${playerData.playerName} (ID: ${playerData.playerId})`); + } catch (err) { + console.error("Erreur lors de l'écriture du fichier HTML :", err); + } + } else { + console.error(`Joueur avec ID "player${playerData.playerId}" non trouvé dans le menu.`); + } + }); + mainWindow.webContents.send("player-info-updated", playerData); + if (inputWindow && !inputWindow.isDestroyed()) { + inputWindow.destroy(); // Ferme la fenêtre après validation + } + } else { + console.error(`⌠Joueuse "${playerData.playerId}" non trouvée.`); + } + } catch (error) { + console.error('Erreur lors de la mise à jour des données :', error); + } +}); + + +ipcMain.on('cancel-player-info', (event) => { + if (inputWindow && !inputWindow.isDestroyed()) { + inputWindow.destroy(); // Ferme la fenêtre après validation + } +}); + + +ipcMain.on('select-player-photo', (event, playerId) => { + dialog.showOpenDialog({ + properties: ['openFile'], + filters: [ + { name: 'Images', extensions: ['jpg', 'jpeg', 'png', 'gif'] } + ] + }).then(result => { + if (!result.canceled && result.filePaths.length > 0) { + const photoPath = result.filePaths[0]; + // Copier l'image dans un dossier dédié de l'application + const photoFileName = `player${playerId}.jpg`; + const destinationPath = path.join(__dirname, 'data','photos', photoFileName); + // Créer le dossier s'il n'existe pas + const photosDir = path.join(__dirname, 'data','photos'); + if (!fs.existsSync(photosDir)) { + fs.mkdirSync(photosDir, { recursive: true }); + } + // Copier le fichier + fs.copyFile(photoPath, destinationPath, (err) => { + if (err) { + console.error('Erreur lors de la copie de la photo:', err); + return; + } + + // Informer le renderer du nouveau chemin de la photo + event.reply('photo-selected', destinationPath); + }); + } + }).catch(err => { + console.error('Erreur lors de la sélection de la photo:', err); + }); +}); \ No newline at end of file diff --git a/Interface/menu.html b/Interface/menu.html index 60ad6dda5d23e4492afcd04016043a5e19c117a6..211d584e398176deb51ac371b3b8cea7e09658eb 100644 --- a/Interface/menu.html +++ b/Interface/menu.html @@ -16,9 +16,9 @@ </a> <div class="collapse" id="collapseLayouts" aria-labelledby="headingOne" data-bs-parent="#sidenavAccordion"> <nav class="sb-sidenav-menu-nested nav"> - <a class="nav-link" href="tables.html" id="playerLisa">Lisa</a> - <a class="nav-link" href="tables.html" id="playerClara">Clara</a> - <a class="nav-link" href="tables.html" id="playerPaulette">Paulette</a><a class="nav-link" href="#" onclick="addPlayer(); return false;" id="addPlayer">+</a> + <a class="nav-link" href="tables.html" id="player1">Martin</a> + <a class="nav-link" href="tables.html" id="player2">Annelise Samson</a> + <a class="nav-link" href="tables.html" id="player3">Jérémy</a><a class="nav-link" href="#" onclick="addPlayer(); return false;" id="addPlayer">+</a> </nav> </div> <a class="nav-link collapsed" href="#" data-bs-toggle="collapse" data-bs-target="#collapsePages" aria-expanded="false" aria-controls="collapsePages"> diff --git a/Interface/poubelle.png b/Interface/poubelle.png index 04c844f5b533f9fff62ad9c33e45749f0af5d61b..33790dc7d2eeee8a482ec8359b4829c68dd0964e 100644 Binary files a/Interface/poubelle.png and b/Interface/poubelle.png differ diff --git a/Interface/preload.js b/Interface/preload.js index e2e77e323edf2c9b67a2356ce86b311261859598..d425494f3990b607271c671dc3583339ac8e618d 100644 --- a/Interface/preload.js +++ b/Interface/preload.js @@ -11,15 +11,23 @@ contextBridge.exposeInMainWorld('electron', { //console.log("Enregistrement du callback pour 'response'"); ipcRenderer.on('response', callback); }, - deleteR: (playerName, date) => ipcRenderer.send('delete-row', playerName, date), + deleteR: (playerId, date, hour) => ipcRenderer.send('delete-row', playerId, date, hour), onRowDeleted: (callback) => ipcRenderer.on('row-deleted', callback), showInputDialog: () => { - //console.log("Événement show-input-dialog envoyé au main process"); ipcRenderer.send("show-input-dialog"); // Envoie l'événement }, - receivePlayerName: (callback) => ipcRenderer.on("player-name-received", (event, playerName) => callback(playerName)), + receivePlayerName: (callback) => ipcRenderer.on("player-name-received", (event, playerId) => callback(playerId)), submitPlayerName: (playerName) => ipcRenderer.send("submit-player-name", playerName), - updateMenu: (playerName) => ipcRenderer.send('update-menu', playerName), + + updateMenu: (playerId) => ipcRenderer.send('update-menu', playerId), onMenuUpdated: (callback) => ipcRenderer.on('menu-updated', callback), + updatePlayerInfo : (playerId) => ipcRenderer.send('update-player-info', playerId), + savePlayerInfoChanges : (playerData) => ipcRenderer.send('save-player-info', playerData), + + cancelPlayerInfoChanges : () => ipcRenderer.send('cancel-player-info'), + onPlayerInfoUpdated: (callback) => ipcRenderer.on("player-info-updated", (event, playerData) => callback(playerData)), + + selectPlayerPhoto: (playerId) => {ipcRenderer.send('select-player-photo', playerId);}, + onPhotoSelected: (callback) => {ipcRenderer.on('photo-selected', (event, photoPath) => {callback(photoPath);});} }); \ No newline at end of file diff --git a/Interface/tables.html b/Interface/tables.html index 394522cc0ec7bd4d6856ee0389c3d549d163cc2d..5aeea6227dc3a172d0fbf8c427fb0c212e6c922b 100644 --- a/Interface/tables.html +++ b/Interface/tables.html @@ -18,7 +18,58 @@ <div id="layoutSidenav_content"> <main> <div class="container-fluid px-4"> - <h1 class="mt-4">Performance</h1> + <h1 class="mt-4" id="playerTitle">Performance</h1> + + <div class="player-card"> + <div class="player-header"> + <img id="playerPhoto" src="default-avatar.jpg" alt="Photo de la joueuse" class="player-photo"> + <h2 id="playerName">Nom de la joueuse</h2> + <img src="edit-icon.png" alt="Modifier" class="edit-icon" id="editPlayer"> + </div> + + <div class="player-details"> + <div class="detail-item"> + <B>Position :</B> + <span id="positionPlayed"></span> + </div> + + <div class="detail-item"> + <B>Date de naissance :</B> + <span id="playerBirthDate"></span> + </div> + + <div class="detail-item"> + <B>Taille :</B> + <span id="playerHeight">...</span> + <span>m</span> + </div> + + <div class="detail-item"> + <B>Poids :</B> + <span id="playerWeight">...</span> + <span>kg</span> + </div> + + <div class="detail-item"> + <B>Attaque :</B> + <span id="playerAttack">...</span> + <span>cm</span> + </div> + + <div class="detail-item"> + <B>Block :</B> + <span id="playerBlockHeight">...</span> + <span>cm</span> + </div> + </div> + + <div class="comment-section"> + <B>Commentaires :</B> + <p id="playerComments">Commentaires sur la joueuse...</p> + </div> + </div> + + <div class="card mb-4"> <div class="card-header"> <i class="fas fa-table me-1"></i> diff --git a/Objet/__pycache__/display.cpython-311.pyc b/Objet/__pycache__/display.cpython-311.pyc index e338aeb771cf6f31bc02f04a2a5d165bef4efae2..7e6753e1edd62c86d99ae01c911a78f5c095fb43 100644 Binary files a/Objet/__pycache__/display.cpython-311.pyc and b/Objet/__pycache__/display.cpython-311.pyc differ diff --git a/Objet/__pycache__/gestion_clavier.cpython-311.pyc b/Objet/__pycache__/gestion_clavier.cpython-311.pyc index 1ddf70342171c8cbcc48e2f4f4ff1ab8c0a1abf7..279d5910c609a4f128b26975390f670ec592c273 100644 Binary files a/Objet/__pycache__/gestion_clavier.cpython-311.pyc and b/Objet/__pycache__/gestion_clavier.cpython-311.pyc differ diff --git a/Objet/__pycache__/parameters.cpython-311.pyc b/Objet/__pycache__/parameters.cpython-311.pyc index 19430169ef99b849616cfc7c91eb2a4806a4b41f..89ec17d9176eee6fa9295a78af3d991641e27c0b 100644 Binary files a/Objet/__pycache__/parameters.cpython-311.pyc and b/Objet/__pycache__/parameters.cpython-311.pyc differ diff --git a/Objet/__pycache__/ui.cpython-311.pyc b/Objet/__pycache__/ui.cpython-311.pyc index 85483b74d7c90215b7d944e0ec46495fae475754..d44d5867c48f7b92671def24eacf9b6e41e1e523 100644 Binary files a/Objet/__pycache__/ui.cpython-311.pyc and b/Objet/__pycache__/ui.cpython-311.pyc differ diff --git a/Objet/__pycache__/video_manager.cpython-311.pyc b/Objet/__pycache__/video_manager.cpython-311.pyc index c623ba62a664db4291ff0bcd6d3ac8e8a776ffc8..5515052c6d606809864a20f978a948770d110a55 100644 Binary files a/Objet/__pycache__/video_manager.cpython-311.pyc and b/Objet/__pycache__/video_manager.cpython-311.pyc differ diff --git a/Objet/main.py b/Objet/main.py index f4e687c1ddda29fc0b0b828878d0358031cc002e..c740e869ff59a0d63db0166d078e291663f2d16a 100644 --- a/Objet/main.py +++ b/Objet/main.py @@ -68,7 +68,7 @@ class Main: cv2.destroyAllWindows() if __name__ == "__main__": - main = Main("vid4.mp4", "video") + main = Main("vid3.mp4", "video") main.run() def is_ready(): diff --git a/Objet/video_manager.py b/Objet/video_manager.py index 5941a34ad034ee5e6faa1b2d1b5e0431968e467f..91aec94570df2d213b8ad77c800b97828187d379 100644 --- a/Objet/video_manager.py +++ b/Objet/video_manager.py @@ -19,10 +19,19 @@ class VideoManager: self.video_type = video_type if self.video_type == "video": self.cap = cv2.VideoCapture(self.video_file) - elif self.video_type == "camera": - self.cam_index = self.select_camera() - self.cam_index = 0 - self.cap = cv2.VideoCapture(self.cam_index) + elif self.video_type == "direct": + max_cameras=10 + backend=cv2.CAP_DSHOW + available_cameras = [] + for i in range(max_cameras): + cap = cv2.VideoCapture(i, backend) + if cap.isOpened(): + ret, frame = cap.read() + if ret: + available_cameras.append(i) + cap.release() + print(available_cameras) + self.cap = cv2.VideoCapture(0) self.fps = int(self.cap.get(cv2.CAP_PROP_FPS)) self.total_frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT)) self.over = False @@ -68,20 +77,24 @@ class VideoManager: def update_frame(self): - frame_time = time.time() - self.current_time - self.current_time = time.time() - self.time = self.current_time - self.start_time - self.current_frame = int(self.cap.get(cv2.CAP_PROP_POS_FRAMES)) - frame_targeted = int(self.time * self.fps) - jump_frame = frame_targeted - self.current_frame - - for _ in range(jump_frame): - ret, self.frame = self.cap.read() - if not ret: - self.over = True - break - self.frame = cv2.resize(self.frame, (self.parameters.width, self.parameters.height)) - self.current_frame += 1 + if self.video_type == "video": + self.current_time = time.time() + self.time = self.current_time - self.start_time + self.current_frame = int(self.cap.get(cv2.CAP_PROP_POS_FRAMES)) + frame_targeted = int(self.time * self.fps) + jump_frame = frame_targeted - self.current_frame + + for _ in range(jump_frame): + ret, self.frame = self.cap.read() + if not ret: + self.over = True + break + self.frame = cv2.resize(self.frame, (self.parameters.width, self.parameters.height)) + self.current_frame += 1 + + elif self.video_type == "direct": + self.update_frame_easy() + self.current_frame += 1 def update_frame_easy(self): _, self.frame = self.cap.read() diff --git "a/__pycache__/chercher_cam\303\251ra.cpython-311.pyc" "b/__pycache__/chercher_cam\303\251ra.cpython-311.pyc" index 184f5a6159bc310caf051e135396901fe985fcee..8ffd2f7914e490cd758c2c24ba0cdcea184b31bd 100644 Binary files "a/__pycache__/chercher_cam\303\251ra.cpython-311.pyc" and "b/__pycache__/chercher_cam\303\251ra.cpython-311.pyc" differ diff --git "a/chercher_cam\303\251ra.py" "b/chercher_cam\303\251ra.py" index a35893138713d40a452a42a552073ef1860b072d..0dbb4d793b333212f10a9662f3f281a07cbe3718 100644 --- "a/chercher_cam\303\251ra.py" +++ "b/chercher_cam\303\251ra.py" @@ -1,47 +1,98 @@ import cv2 import tkinter as tk from tkinter import ttk +from PIL import Image, ImageTk +import threading -def detect_cameras(): - """Détecte les caméras connectées à l'ordinateur.""" - cameras = [] - for i in range(10): # Vérifie les 10 premiers indices de caméra - cap = cv2.VideoCapture(i) - if cap.isOpened(): - cameras.append(i) - cap.release() - return cameras - -def select_camera(): - """Affiche une interface Tkinter pour sélectionner une caméra.""" - cameras = detect_cameras() - if not cameras: - print("Aucune caméra détectée.") - return None - - def on_select(): - nonlocal selected_camera - selected_camera = int(camera_var.get()) - root.destroy() - - root = tk.Tk() - root.title("Sélection de la caméra") - - tk.Label(root, text="Sélectionnez une caméra :").pack(pady=10) - - camera_var = tk.StringVar(value=str(cameras[0])) - for cam in cameras: - ttk.Radiobutton(root, text=f"Caméra {cam}", variable=camera_var, value=str(cam)).pack(anchor=tk.W) - - ttk.Button(root, text="Valider", command=on_select).pack(pady=10) - - selected_camera = None - root.mainloop() - return selected_camera +class CameraSelector: + def __init__(self, root): + self.root = root + self.root.title("Sélection de caméra") + self.cameras = [] + self.current_camera = None + self.video_source = None + + # Détection des caméras disponibles + self.detect_cameras() + + # Interface graphique + self.create_widgets() + + def detect_cameras(self): + """Détecte toutes les caméras disponibles jusqu'à l'index 10""" + self.cameras = [] + for i in range(10): # Vous pouvez augmenter ce nombre si nécessaire + cap = cv2.VideoCapture(i) + if cap.isOpened(): + self.cameras.append(i) + cap.release() + + def create_widgets(self): + """Crée l'interface utilisateur""" + # Cadre principal + main_frame = ttk.Frame(self.root, padding=10) + main_frame.pack() + + # Sélection de caméra + ttk.Label(main_frame, text="Caméras détectées:").pack() + self.camera_var = tk.StringVar() + self.cam_selector = ttk.Combobox(main_frame, textvariable=self.camera_var) + self.cam_selector['values'] = [f"Caméra {i}" for i in self.cameras] + self.cam_selector.pack(pady=5) + + # Bouton de confirmation + ttk.Button(main_frame, text="Ouvrir", command=self.start_camera).pack(pady=5) + + # Zone d'affichage vidéo + self.video_label = ttk.Label(main_frame) + self.video_label.pack() + + def start_camera(self): + """Démarre le flux vidéo de la caméra sélectionnée""" + if self.current_camera is not None: + self.stop_camera() + + selected = self.cam_selector.current() + if selected == -1: + return + + self.video_source = self.cameras[selected] + self.current_camera = cv2.VideoCapture(self.video_source) + + # Démarrer l'affichage vidéo dans un thread séparé + self.thread = threading.Thread(target=self.show_video) + self.thread.daemon = True + self.thread.start() + + def show_video(self): + """Affiche le flux vidéo dans le label""" + while self.current_camera.isOpened(): + ret, frame = self.current_camera.read() + if ret: + # Conversion de l'image pour Tkinter + frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + img = Image.fromarray(frame) + imgtk = ImageTk.PhotoImage(image=img) + + # Mise à jour de l'interface + self.video_label.configure(image=imgtk) + self.video_label.image = imgtk + else: + break + + def stop_camera(self): + """Arrête le flux vidéo""" + if self.current_camera is not None: + self.current_camera.release() + self.video_label.configure(image='') + self.video_label.image = None + + def on_close(self): + self.stop_camera() + self.root.destroy() if __name__ == "__main__": - camera_index = select_camera() - if camera_index is not None: - print(f"Caméra sélectionnée : {camera_index}") - else: - print("Aucune caméra sélectionnée.") \ No newline at end of file + root = tk.Tk() + app = CameraSelector(root) + root.protocol("WM_DELETE_WINDOW", app.on_close) + root.mainloop() \ No newline at end of file diff --git a/vid3.mp4 b/vid3.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..fdc50934648d989c26de3a8c4ac298b49ac8c3c4 Binary files /dev/null and b/vid3.mp4 differ