update system

This commit is contained in:
Louis Mazin 2025-08-19 19:36:27 +02:00
parent dd43bf5abf
commit 7ae16570d5
7 changed files with 117 additions and 5 deletions

View File

@ -18,3 +18,16 @@ class AlertManager:
error_text = self.language_manager.get_text(error_key)
QMessageBox.critical(parent, error_title, error_text)
def show_choice(self, message: str, parent=None) -> bool:
box = QMessageBox(parent)
box.setWindowTitle(self.language_manager.get_text("confirmation"))
box.setText(message)
box.setIcon(QMessageBox.Icon.Question)
yes = box.addButton(QMessageBox.StandardButton.Yes)
no = box.addButton(QMessageBox.StandardButton.No)
yes.setText(self.language_manager.get_text("yes"))
no.setText(self.language_manager.get_text("no"))
box.setDefaultButton(yes)
box.exec()
return box.clickedButton() == yes

View File

@ -3,6 +3,7 @@ from app.core.language_manager import LanguageManager
from app.core.theme_manager import ThemeManager
from app.core.settings_manager import SettingsManager
from app.core.alert_manager import AlertManager
from app.core.update_manager import UpdateManager
from typing import Optional
class MainManager:
@ -18,6 +19,7 @@ class MainManager:
self.settings_manager: SettingsManager = SettingsManager(self.observer_manager, self.theme_manager)
self.language_manager: LanguageManager = LanguageManager(self.settings_manager)
self.alert_manager: AlertManager = AlertManager(self.language_manager, self.theme_manager)
self.update_manager: UpdateManager = UpdateManager(self.settings_manager, self.language_manager, self.alert_manager)
@classmethod
def get_instance(cls) -> 'MainManager':
@ -39,3 +41,6 @@ class MainManager:
def get_alert_manager(self) -> AlertManager:
return self.alert_manager
def get_update_manager(self) -> UpdateManager:
return self.update_manager

View File

@ -0,0 +1,80 @@
import requests
from packaging import version
from PyQt6.QtWidgets import QFileDialog
from app.core.alert_manager import AlertManager
from app.core.settings_manager import SettingsManager
from app.core.language_manager import LanguageManager
import os
import sys
import subprocess
class UpdateManager:
def __init__(self, settings_manager: SettingsManager, language_manager: LanguageManager, alert_manager: AlertManager) -> None:
self.settings_manager = settings_manager
self.language_manager = language_manager
self.alert_manager = alert_manager
self.repo_url = self.settings_manager.get_config("git_repo")
self.app_name = self.settings_manager.get_config("app_name").replace(" ","_")
self.app_os = self.settings_manager.get_config("app_os")
self.arch = self.settings_manager.get_config("architecture")
self.extension = "exe" if self.app_os.lower() == "windows" else "AppImage" # adapte selon OS
def get_latest_release_with_asset(self) -> dict:
# Récupère la release la plus récente qui contient le bon fichier
try:
if "gitea" in self.repo_url:
owner_repo = self.repo_url.split("/")[-2:]
api_url = self.repo_url.replace(owner_repo[0], "api/v1/repos/" + owner_repo[0]) + "/releases"
resp = requests.get(api_url)
releases = resp.json()
else:
owner_repo = self.repo_url.split("/")[-2:]
api_url = f"https://api.github.com/repos/{owner_repo[0]}/{owner_repo[1]}/releases"
resp = requests.get(api_url)
releases = resp.json()
# Cherche le bon asset dans chaque release
expected_filename = f"{self.app_name}-{self.app_os}-{self.arch}.{self.extension}"
for release in releases:
for asset in release.get("assets", []):
if asset.get("name", "") == expected_filename:
return {
"tag_name": release.get("tag_name"),
"download_url": asset.get("browser_download_url")
}
except Exception:
pass
return None
def check_for_update(self, parent=None) -> bool:
current_version = self.settings_manager.get_config("app_version")
release = self.get_latest_release_with_asset()
if release and version.parse(release["tag_name"]) > version.parse(current_version):
choice = self.alert_manager.show_choice(
self.language_manager.get_text("update_found").replace("{latest_tag}", release["tag_name"]),
parent=parent
)
if choice:
folder = QFileDialog.getExistingDirectory(parent, self.language_manager.get_text("choose_update_folder"))
if folder:
self.download(release["download_url"], folder, parent)
return True
return False
def download(self, download_url, folder, parent=None):
try:
filename = os.path.basename(download_url)
local_path = os.path.join(folder, filename)
resp = requests.get(download_url, stream=True)
with open(local_path, "wb") as f:
for chunk in resp.iter_content(chunk_size=8192):
f.write(chunk)
msg = self.language_manager.get_text("update_downloaded").replace("{local_path}", local_path)
self.alert_manager.show_success(msg, parent=parent)
# Ouvre le fichier téléchargé
if sys.platform.startswith("win"):
os.startfile(local_path)
else:
subprocess.Popen(["chmod", "+x", local_path])
subprocess.Popen([local_path])
except Exception:
self.alert_manager.show_error("update_download_error", parent=parent)

View File

@ -6,5 +6,5 @@
"architecture": "x64",
"icon_path": "data/assets/icon.ico",
"main_script": "main.py",
"git_repo": "https://gitea.louismazin.ovh/LouisMazin/HoDA"
"git_repo": "https://gitea.louismazin.ovh/LouisMazin/PythonApplicationTemplate"
}

View File

@ -13,8 +13,13 @@
"sending": "Sending...",
"success": "Success",
"error": "Error",
"confirmation": "Confirmation",
"suggestion_sent_success": "Your message has been sent successfully!",
"suggestion_send_error": "Error sending message. Try again later.",
"email_credentials_error": "Email credentials not or bad configured. Please set your email and password in the .env file.",
"suggestion_too_short": "The message must be at least 15 characters long."
"suggestion_too_short": "The message must be at least 15 characters long.",
"update_found": "New version available: {latest_tag} \nDo you want to install the update?",
"choose_update_folder": "Choose destination folder",
"update_downloaded": "Update downloaded to {local_path}",
"update_download_error": "Error downloading update"
}

View File

@ -13,8 +13,13 @@
"sending": "Envoi...",
"success": "Succès",
"error": "Erreur",
"confirmation": "Confirmation",
"suggestion_sent_success": "Votre message a été envoyé avec succès !",
"suggestion_send_error": "Erreur lors de l'envoi du message. Essayez à nouveau plus tard.",
"email_credentials_error": "Identifiants de messagerie non ou mal configurés. Veuillez définir votre email et mot de passe dans le fichier .env.",
"suggestion_too_short": "Le message doit contenir au moins 15 caractères."
"suggestion_too_short": "Le message doit contenir au moins 15 caractères.",
"update_found": "Nouvelle version disponible : {latest_tag} \nVoulez-vous installer la mise à jour ?",
"choose_update_folder": "Choisissez le dossier de destination",
"update_downloaded": "Mise à jour téléchargée dans {local_path}",
"update_download_error": "Erreur lors du téléchargement de la mise à jour"
}

View File

@ -5,15 +5,19 @@ from PyQt6.QtGui import QIcon
from app.ui.main_window import MainWindow
from app.core.main_manager import MainManager
def main() -> int:
main_manager: MainManager = MainManager.get_instance()
theme_manager = main_manager.get_theme_manager()
settings_manager = main_manager.get_settings_manager()
update_manager = main_manager.get_update_manager() # Ajout
app: QApplication = QApplication(sys.argv)
app.setStyleSheet(theme_manager.get_sheet())
app.setApplicationName(settings_manager.get_config("app_name"))
app.setWindowIcon(QIcon(paths.get_asset_path("icon")))
if update_manager.check_for_update():
return
window: MainWindow = MainWindow()
window.show()
return app.exec()