Skip to content

Commit 55f9de3

Browse files
committed
Add GitHub icon to assets/icons directory
1 parent 2de2a47 commit 55f9de3

7 files changed

Lines changed: 182 additions & 56 deletions

File tree

.gitignore

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
11
*.html
2-
*.jpg
3-
*.jpeg
4-
*.bmp
5-
*.gif
6-
*.pdf
72
*.db
83
*.log
94

assets/icons/github.png

14.5 KB
Loading

assets/strings/en.json

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,38 @@
33
"search": "Search",
44
"clear": "Clear",
55
"mobile": "Mobile",
6-
"results_title": "🔎 ANALYSIS RESULTS",
6+
"results_title": "ANALYSIS RESULTS",
77
"map": "Map",
88
"info": "Info",
9-
"diary": "Diary",
9+
"diary": "Journal",
1010
"pdf": "Export PDF",
1111
"link": "Link",
1212
"settings": "Settings",
13-
"crop_image": "Crop image?",
14-
"crop_yes": "Crop around object",
15-
"crop_no": "Keep full image",
16-
"analysis_start_0": "Analysis in progress The AI is inspecting the bug 🧐",
17-
"analysis_start_1": "Analyzing... get comfortable, it's coffee break time",
18-
"analysis_start_2": "Analysis in progress - patience, science is working",
19-
"analysis_error_0": "Oops - analysis stumbled. The AI is making a cup of tea ☕",
13+
"crop_image": "Crop the image?",
14+
"crop_yes": "Crop around the object",
15+
"crop_no": "Keep the whole image",
16+
"analysis_start_0": "Analysis in progress... The AI is examining the critter",
17+
"analysis_start_1": "Analyzing... make yourself comfortable, it takes a coffee break ☕",
18+
"analysis_start_2": "Analysis in progress - patience, science is at work",
19+
"analysis_error_0": "Oops - the analysis stumbled. The AI is going to have a cup of tea ☕",
2020
"analysis_error_1": "Error during analysis - try again or check the image.",
21-
"model_loaded_0": "Model loaded\\nready to detect bugs",
22-
"model_loaded_1": "Model ready \\nlet the hunt begin!",
23-
"model_loaded_2": "Model loaded\\nthe AI is awake (coffee consumed)",
24-
"model_missing_0": "No idea how you got this error but the model is not loaded ❌",
25-
"model_missing_1": "Model missing - it's on vacation 🏖️",
26-
"model_missing_2": "Model not found - it's playing hide and seek 🫣",
21+
"model_loaded_0": "Model loaded\nready to detect critters",
22+
"model_loaded_1": "Model ready\nlet the hunt begin!",
23+
"model_loaded_2": "Model loaded\nAI is awake (coffee consumed)",
24+
"model_missing_0": "I don't know how you managed to get this error but the model is not loaded ❌",
25+
"model_missing_1": "Model missing - it's on vacation",
26+
"model_missing_2": "Model not found - playing hide and seek",
2727
"image_loaded_0": "Image loaded - nice catch!",
28-
"image_loaded_1": "Image received 🖼️ - get your magnifiers ready",
28+
"image_loaded_1": "Image received - prepare the magnifying glasses",
2929
"image_loaded_2": "Image loaded - ready for analysis!",
30-
"analysis_done_0": "Analysis complete",
31-
"analysis_done_1": "It's in the box! Results ready 📊",
32-
"no_model_0": "No model loaded. Can't analyze (the model ran away).",
33-
"no_model_1": "No arms, no chocolate. Wait, no model, no analysis!",
30+
"analysis_done_0": "Analysis complete",
31+
"analysis_done_1": "It's in the box! Results ready!",
32+
"no_model_0": "No model loaded. Cannot analyze (the model fled).",
33+
"no_model_1": "No arms, no chocolate. Oh no, no model, no analysis!",
3434
"ready_0": "Ready",
3535
"ready_1": "Ready - ready to hunt insects!",
36-
"ready_2": "Ready (in standby mode, but operational)",
37-
"app_title": "🦋 Open Insect Identifier",
36+
"ready_2": "Ready (on standby, but operational)",
37+
"app_title": "Open Insect Identifier",
3838
"no_image_selected": "No image selected",
3939
"no_images_found": "No images found",
4040
"loading_images": "Loading images…",
@@ -43,9 +43,9 @@
4343
"main_button": "Main button color",
4444
"hover_button": "Button hover color",
4545
"background": "Background color",
46-
"text_color": "Text color",
4746
"widget_background": "Widget background color",
48-
"restart_warning": "To apply changes to the main menu, you must restart Open Insect Identifier!",
47+
"text_color": "Text color",
48+
"restart_warning": "To apply changes to the main menu, you need to restart Open Insect Identifier!",
4949
"change": "Change",
5050
"button_upload": "Upload Image",
5151
"button_identify": "Identify",
@@ -54,14 +54,14 @@
5454
"geo_missing": "No geographic data for {name}",
5555
"welcome": "Upload an image to identify the insect",
5656
"no_image": "Please upload an image first",
57-
"error_load_image": "Unable to load image",
58-
"error_load_model": "Unable to load model",
59-
"error_analyze": "Oops, something went wrong",
60-
"success": "ANALYSIS RESULTS",
57+
"error_load_image": "Cannot load image",
58+
"error_load_model": "Cannot load model",
59+
"error_analyze": "Oops, it's not working",
60+
"success": "ANALYSIS RESULTS",
6161
"confidence_title": "Confidence",
62-
"sure": "Sure",
62+
"positive": "Confident",
6363
"ambiguous": "Ambiguous",
64-
"unsure": "Unsure",
64+
"negative": "Unreliable",
6565
"analysis_success": "Analysis successful!",
6666
"no_wikipedia_summary": "No Wikipedia summary available."
6767
}

assets/strings/fr.json

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"search": "Rechercher",
44
"clear": "Effacer",
55
"mobile": "Mobile",
6-
"results_title": "🔎 RÉSULTATS DE L'ANALYSE",
6+
"results_title": "RÉSULTATS DE L'ANALYSE",
77
"map": "Carte",
88
"info": "Infos",
99
"diary": "Journal",
@@ -13,28 +13,28 @@
1313
"crop_image": "Recadrer l'image ?",
1414
"crop_yes": "Recadrer autour de l'objet",
1515
"crop_no": "Garder l'image entière",
16-
"analysis_start_0": "Analyse en cours… L'IA scrute la bestiole 🧐",
16+
"analysis_start_0": "Analyse en cours… L'IA scrute la bestiole",
1717
"analysis_start_1": "On analyse... mets-toi à l'aise, ça prend une coffee break ☕",
1818
"analysis_start_2": "Analyse en cours - patience, la science travaille",
1919
"analysis_error_0": "Oops - l'analyse a trébuché. L'IA va se faire une tasse de thé ☕",
2020
"analysis_error_1": "Erreur durant l'analyse - réessaie ou vérifie l'image.",
21-
"model_loaded_0": "Modèle chargé\\nprêt à détecter des bestioles",
22-
"model_loaded_1": "Modèle prêt \\nque la chasse commence!",
23-
"model_loaded_2": "Modèle chargé\\nl'IA est éveillée (café consommé)",
21+
"model_loaded_0": "Modèle chargé\nprêt à détecter des bestioles",
22+
"model_loaded_1": "Modèle prêt\nque la chasse commence!",
23+
"model_loaded_2": "Modèle chargé\nl'IA est éveillée (café consommé)",
2424
"model_missing_0": "Je ne sais pas du tout comment tu as fait pour avoir cette erreur mais le modèle n'est pas chargé ❌",
25-
"model_missing_1": "Modèle absent - il a pris des vacances 🏖️",
26-
"model_missing_2": "Modèle introuvable - il joue à cache-cache 🫣",
25+
"model_missing_1": "Modèle absent - il a pris des vacances",
26+
"model_missing_2": "Modèle introuvable - il joue à cache-cache",
2727
"image_loaded_0": "Image chargée - belle prise!",
28-
"image_loaded_1": "Image reçue 🖼️ - prépare les loupes",
28+
"image_loaded_1": "Image reçue - prépare les loupes",
2929
"image_loaded_2": "Image chargée - prêts pour l'analyse!",
30-
"analysis_done_0": "Analyse terminée",
31-
"analysis_done_1": "C'est dans la boîte! Résultats prêts 📊",
30+
"analysis_done_0": "Analyse terminée",
31+
"analysis_done_1": "C'est dans la boîte! Résultats prêts !",
3232
"no_model_0": "Aucun modèle chargé. Impossible d'analyser (le modèle a fui).",
3333
"no_model_1": "Pas de bras, pas de chocolat. Ah non, pas de modèle, pas d'analyse!",
3434
"ready_0": "Prêt",
3535
"ready_1": "Prêt - prêt à chasser des insectes!",
3636
"ready_2": "Prêt (en mode veille, mais opérationnel)",
37-
"app_title": "🦋 Open Insect Identifier",
37+
"app_title": "Open Insect Identifier",
3838
"no_image_selected": "Aucune image sélectionnée",
3939
"no_images_found": "Pas d'images trouvées",
4040
"loading_images": "Chargement des images…",
@@ -57,7 +57,7 @@
5757
"error_load_image": "Impossible de charger l'image",
5858
"error_load_model": "Impossible de charger le modèle",
5959
"error_analyze": "Oups bah ça marche pas",
60-
"success": "RÉSULTATS DE L'ANALYSE",
60+
"success": "RÉSULTATS DE L'ANALYSE",
6161
"confidence_title": "Confiance",
6262
"positive": "Sûr",
6363
"ambiguous": "Ambigu",

config.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
# The default colors for the interface
1111
DEFAULTS_COLORS = {
1212
"primary_color": "#1f6aa5",
13-
"hover_color": "#195985",
14-
"background": "#000000",
13+
"hover_color": "#195985",
14+
"background": "#000000",
1515
"widget_background": "#1e1e1e",
16-
"text": "#DCE4EE",
16+
"text": "#DCE4EE",
1717
}
1818

1919
# Appearance (for KT)
@@ -43,8 +43,32 @@
4343
"positive": "positive.png",
4444
"negative": "negative.png",
4545
"ambiguous": "ambiguous.png",
46+
"github": "github.png",
4647
}
4748

49+
CONTRIBUTORS = [
50+
{
51+
"name": "Yoann",
52+
"icon": "https://avatars.githubusercontent.com/u/182555207?s=64&v=4",
53+
"url": " https://github.com/YoannDev90",
54+
},
55+
{
56+
"name": "Lucas",
57+
"icon": "https://avatars.githubusercontent.com/u/85549951?s=64&v=4",
58+
"url": "https://github.com/LuckyTheCookie",
59+
},
60+
{
61+
"name": "Clovis",
62+
"icon": "https://avatars.githubusercontent.com/u/150185321?s=64&v=4",
63+
"url": "https://github.com/Elnix90",
64+
},
65+
{
66+
"name": "Nathanael",
67+
"icon": "https://avatars.githubusercontent.com/u/247614572?s=64&v=4",
68+
"url": "https://github.com/NathanaelRBDev",
69+
},
70+
]
71+
4872
# Dimensions
4973
WINDOW_SIZE = {"width": 1200, "height": 800}
5074
WINDOW_STATE = "maximized" # normal, maximized

ui/export.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def export_report(self):
3232
file_path = filedialog.asksaveasfilename(
3333
defaultextension=".pdf",
3434
filetypes=[("PDF", "*.pdf")],
35+
initialdir=os.path.expanduser("~/Documents"),
3536
initialfile=f"{suggested_name}.pdf",
3637
title=self.i18n.t("pdf") if hasattr(self, "i18n") else "Exporter en PDF",
3738
)

ui/sidebar.py

Lines changed: 112 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,77 @@
1+
from io import BytesIO
12
import os
23
import webbrowser
4+
from PIL import Image, ImageDraw
35
import customtkinter as ctk
6+
import requests
47
import config
58
from utils.logger import setup_logger
69

710
logger = setup_logger(__name__)
811

912

13+
# Tooltip simple pour CustomTkinter
14+
class ToolTip:
15+
def __init__(self, widget, text):
16+
self.widget = widget
17+
self.text = text
18+
self.tooltip = None
19+
self.widget.bind("<Enter>", self.show_tooltip)
20+
self.widget.bind("<Leave>", self.hide_tooltip)
21+
22+
def show_tooltip(self, event=None):
23+
if self.tooltip or not self.text:
24+
return
25+
x = self.widget.winfo_rootx() + self.widget.winfo_width() // 2
26+
y = self.widget.winfo_rooty() + self.widget.winfo_height() + 5
27+
self.tooltip = ctk.CTkToplevel(self.widget)
28+
self.tooltip.wm_overrideredirect(True)
29+
self.tooltip.wm_geometry(f"+{x}+{y}")
30+
label = ctk.CTkLabel(
31+
self.tooltip,
32+
text=self.text,
33+
font=ctk.CTkFont(size=12),
34+
fg_color=("gray90", "gray20"),
35+
corner_radius=5,
36+
padx=10,
37+
pady=5,
38+
)
39+
label.pack()
40+
41+
def hide_tooltip(self, event=None):
42+
if self.tooltip:
43+
self.tooltip.destroy()
44+
self.tooltip = None
45+
46+
47+
def make_circle_image(image, size):
48+
"""Crée une image circulaire à partir d'une image carrée ou rectangulaire."""
49+
# Convertir en RGBA si nécessaire
50+
if image.mode != "RGBA":
51+
image = image.convert("RGBA")
52+
53+
# Créer un masque circulaire
54+
mask = Image.new("L", (size, size), 0)
55+
draw = ImageDraw.Draw(mask)
56+
draw.ellipse((0, 0, size - 1, size - 1), fill=255)
57+
58+
# Redimensionner l'image pour qu'elle soit carrée
59+
image = image.resize((size, size), Image.Resampling.LANCZOS)
60+
61+
# Appliquer le masque
62+
image.putalpha(mask)
63+
return image
64+
65+
1066
class Sidebar(ctk.CTkFrame):
1167
def __init__(self, master, icons, i18n=None, **kwargs):
1268
super().__init__(master, width=260, corner_radius=0, **kwargs)
1369
self.icons = icons
1470
self.gbif_url = None
1571
self.i18n = i18n
1672

17-
# Grille
18-
self.grid_rowconfigure(10, weight=1)
73+
# Grille - augmenter le nombre de lignes pour les contributeurs
74+
self.grid_rowconfigure(12, weight=1)
1975

2076
# Récupération des styles depuis config.py
2177
btn_height = config.THEME.get("btn_height", 45)
@@ -25,10 +81,10 @@ def __init__(self, master, icons, i18n=None, **kwargs):
2581

2682
self.lbl_logo = ctk.CTkLabel(
2783
self,
28-
text=self.i18n.t("app_title") if self.i18n else "Open Insect\nIdentifier",
84+
text=self.i18n.t("app_title"),
2985
font=ctk.CTkFont(size=22, weight="bold"),
3086
)
31-
self.lbl_logo.grid(row=0, column=0, padx=20, pady=(30, 20))
87+
self.lbl_logo.grid(row=0, column=0, padx=20, pady=20, sticky="n")
3288

3389
self.btn_upload = ctk.CTkButton(
3490
self,
@@ -64,6 +120,7 @@ def __init__(self, master, icons, i18n=None, **kwargs):
64120
text=self.i18n.t("clear") if self.i18n else "Effacer",
65121
image=self.icons.get("clear"),
66122
compound="left",
123+
font=ctk.CTkFont(size=14, weight="bold"),
67124
height=btn_height,
68125
state="disabled",
69126
fg_color=primary_color,
@@ -160,9 +217,58 @@ def __init__(self, master, icons, i18n=None, **kwargs):
160217
)
161218
self.btn_settings.grid(row=9, column=0, padx=20, pady=10, sticky="ew")
162219

220+
# Bouton GitHub (juste après Settings)
221+
self.button_github_orga = ctk.CTkButton(
222+
self,
223+
text="GitHub",
224+
image=self.icons.get("github"),
225+
compound="left",
226+
font=ctk.CTkFont(size=14, weight="bold"),
227+
height=btn_height,
228+
fg_color=primary_color,
229+
hover_color=hover_color,
230+
text_color=text_color,
231+
command=lambda: webbrowser.open("https://github.com/Open-Insect-Id/"),
232+
)
233+
self.button_github_orga.grid(row=10, column=0, padx=20, pady=5, sticky="ew")
234+
235+
# Frame pour les contributeurs (icônes côte à côte)
236+
contrib_frame = ctk.CTkFrame(self, fg_color="transparent")
237+
contrib_frame.grid(row=11, column=0, padx=20, pady=5, sticky="ew")
238+
contrib_frame.grid_columnconfigure((0, 1, 2, 3), weight=1)
239+
240+
# Charger les icônes des contributeurs
241+
self.contributor_buttons = []
242+
for i, contrib in enumerate(config.CONTRIBUTORS[:4]): # Limiter à 4
243+
try:
244+
# Télécharger l'icône
245+
resp = requests.get(contrib["icon"], timeout=10)
246+
img = Image.open(BytesIO(resp.content))
247+
# Créer une image circulaire de 40x40
248+
img = make_circle_image(img, 40)
249+
ctk_img = ctk.CTkImage(light_image=img, dark_image=img, size=(40, 40))
250+
251+
btn = ctk.CTkButton(
252+
contrib_frame,
253+
text="", # Pas de texte
254+
image=ctk_img,
255+
width=40,
256+
height=40,
257+
fg_color=primary_color,
258+
hover_color=hover_color,
259+
text_color=text_color,
260+
command=lambda url=contrib["url"]: webbrowser.open(url),
261+
)
262+
btn.grid(row=0, column=i, padx=2, pady=5)
263+
# Ajouter tooltip avec le nom
264+
ToolTip(btn, contrib["name"])
265+
self.contributor_buttons.append(btn)
266+
except Exception as e:
267+
logger.error(f"Erreur chargement icône contrib {contrib['name']}: {e}")
268+
163269
# Zone de statut en bas de la sidebar
164270
self.status_frame = ctk.CTkFrame(self, fg_color="transparent")
165-
self.status_frame.grid(row=10, column=0, padx=20, pady=20, sticky="ew")
271+
self.status_frame.grid(row=12, column=0, padx=20, pady=20, sticky="ew")
166272

167273
self.lbl_status = ctk.CTkLabel(
168274
self.status_frame,
@@ -174,7 +280,7 @@ def __init__(self, master, icons, i18n=None, **kwargs):
174280
text_color="gray60",
175281
wraplength=200,
176282
)
177-
self.lbl_status.pack(pady=5, fill="x")
283+
self.lbl_status.grid(pady=5, sticky="ew")
178284

179285
def update_status(self, text):
180286
logger.info(f"Statut mis à jour: {text}")

0 commit comments

Comments
 (0)