suggestions tab added, state and size save in progress
This commit is contained in:
parent
9a61d20a57
commit
fb44f09610
@ -3,7 +3,7 @@ import json
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# Load config.json
|
# Load config.json
|
||||||
config_path = Path("config.json")
|
config_path = Path("../config.json")
|
||||||
with config_path.open("r", encoding="utf-8") as f:
|
with config_path.open("r", encoding="utf-8") as f:
|
||||||
config = json.load(f)
|
config = json.load(f)
|
||||||
|
|
||||||
@ -24,7 +24,8 @@ icon = getenv("ICON_PATH", "")
|
|||||||
# Data files to bundle
|
# Data files to bundle
|
||||||
datas = [
|
datas = [
|
||||||
("data/assets/*", "data/assets/"),
|
("data/assets/*", "data/assets/"),
|
||||||
("data/", "data/")
|
("data/", "data/"),
|
||||||
|
("config.json", ".")
|
||||||
]
|
]
|
||||||
binaries = []
|
binaries = []
|
||||||
|
|
||||||
|
@ -18,8 +18,7 @@ class SettingsManager:
|
|||||||
with open(defaults_path, 'r', encoding='utf-8') as f:
|
with open(defaults_path, 'r', encoding='utf-8') as f:
|
||||||
self.default_settings = json.load(f)
|
self.default_settings = json.load(f)
|
||||||
|
|
||||||
config_path = path.join(paths.get_current_dir(), "config.json")
|
with open(paths.resource_path("config.json"), 'r', encoding='utf-8') as f:
|
||||||
with open(config_path, 'r', encoding='utf-8') as f:
|
|
||||||
self.config = json.load(f)
|
self.config = json.load(f)
|
||||||
|
|
||||||
self.settings = QSettings(path.join(paths.get_user_data_dir(self.get_config("app_name")), self.get_config("app_name") + ".ini"), QSettings.Format.IniFormat)
|
self.settings = QSettings(path.join(paths.get_user_data_dir(self.get_config("app_name")), self.get_config("app_name") + ".ini"), QSettings.Format.IniFormat)
|
||||||
@ -49,7 +48,7 @@ class SettingsManager:
|
|||||||
self.settings.setValue("lang", lang_code)
|
self.settings.setValue("lang", lang_code)
|
||||||
self.observer_manager.notify(NotificationType.LANGUAGE)
|
self.observer_manager.notify(NotificationType.LANGUAGE)
|
||||||
|
|
||||||
# Window size and fullscreen
|
# Window size and maximized
|
||||||
def get_window_size(self) -> dict:
|
def get_window_size(self) -> dict:
|
||||||
return self.settings.value("window_size", self.default_settings.get("window_size"))
|
return self.settings.value("window_size", self.default_settings.get("window_size"))
|
||||||
|
|
||||||
@ -59,18 +58,8 @@ class SettingsManager:
|
|||||||
new_size = {"width": width, "height": height}
|
new_size = {"width": width, "height": height}
|
||||||
self.settings.setValue("window_size", new_size)
|
self.settings.setValue("window_size", new_size)
|
||||||
|
|
||||||
def get_fullscreen(self) -> bool:
|
def get_maximized(self) -> bool:
|
||||||
return self.settings.value("fullscreen", self.default_settings.get("fullscreen"))
|
return self.settings.value("maximized", self.default_settings.get("maximized")) == "true"
|
||||||
|
|
||||||
def set_fullscreen(self, fullscreen: bool, width: int, height: int):
|
def set_maximized(self, maximized: bool):
|
||||||
self.settings.setValue("fullscreen", fullscreen)
|
self.settings.setValue("maximized", maximized)
|
||||||
self.settings.setValue("fullscreen_size", {"width": width, "height": height})
|
|
||||||
|
|
||||||
def get_fullscreen_size(self) -> dict:
|
|
||||||
return self.settings.value("fullscreen_size", self.default_settings.get("fullscreen_size"))
|
|
||||||
|
|
||||||
def set_fullscreen_size(self, width: int, height: int) -> None:
|
|
||||||
current_size = self.get_fullscreen_size()
|
|
||||||
if current_size["width"] != width or current_size["height"] != height:
|
|
||||||
new_size = {"width": width, "height": height}
|
|
||||||
self.settings.setValue("fullscreen_size", new_size)
|
|
@ -1,9 +1,11 @@
|
|||||||
from PyQt6.QtWidgets import QMainWindow
|
from PyQt6.QtWidgets import QMainWindow
|
||||||
from PyQt6.QtGui import QIcon
|
from PyQt6.QtGui import QIcon
|
||||||
from PyQt6.QtWidgets import QApplication
|
from PyQt6.QtWidgets import QApplication
|
||||||
|
from PyQt6.QtCore import QSize
|
||||||
from app.core.main_manager import MainManager, NotificationType
|
from app.core.main_manager import MainManager, NotificationType
|
||||||
from app.ui.widgets.tabs_widget import TabsWidget, MenuDirection, ButtonPosition, BorderSide
|
from app.ui.widgets.tabs_widget import TabsWidget, MenuDirection, ButtonPosition, BorderSide
|
||||||
from app.ui.windows.settings_window import SettingsWindow
|
from app.ui.windows.settings_window import SettingsWindow
|
||||||
|
from app.ui.windows.suggestion_window import SuggestionWindow
|
||||||
import app.utils.paths as paths
|
import app.utils.paths as paths
|
||||||
|
|
||||||
class MainWindow(QMainWindow):
|
class MainWindow(QMainWindow):
|
||||||
@ -11,6 +13,7 @@ class MainWindow(QMainWindow):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.main_manager = MainManager()
|
self.main_manager = MainManager()
|
||||||
|
|
||||||
self.language_manager = self.main_manager.get_language_manager()
|
self.language_manager = self.main_manager.get_language_manager()
|
||||||
self.theme_manager = self.main_manager.get_theme_manager()
|
self.theme_manager = self.main_manager.get_theme_manager()
|
||||||
self.settings_manager = self.main_manager.get_settings_manager()
|
self.settings_manager = self.main_manager.get_settings_manager()
|
||||||
@ -19,24 +22,62 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
# Configurer la fenêtre avant de créer les widgets
|
# Configurer la fenêtre avant de créer les widgets
|
||||||
app = QApplication.instance()
|
app = QApplication.instance()
|
||||||
self.settings_manager.dpi = app.primaryScreen().devicePixelRatio()
|
|
||||||
size = app.primaryScreen().size()
|
size = app.primaryScreen().size()
|
||||||
self.settings_manager.minScreenSize = min(size.height(),size.width())
|
self.settings_manager.minScreenSize = min(size.height(),size.width())
|
||||||
configWidth = int(self.settings_manager.get_fullscreen_size()["width"] if self.settings_manager.get_fullscreen() else self.settings_manager.get_window_size()["width"] /self.settings_manager.dpi)
|
|
||||||
configHeight = int(self.settings_manager.get_fullscreen_size()["height"] if self.settings_manager.get_fullscreen() else self.settings_manager.get_window_size()["height"] /self.settings_manager.dpi)
|
|
||||||
self.setMinimumSize(600, 400)
|
self.setMinimumSize(600, 400)
|
||||||
self.resize(configWidth, configHeight)
|
|
||||||
self.setWindowTitle(self.settings_manager.get_config("app_name"))
|
self.setWindowTitle(self.settings_manager.get_config("app_name"))
|
||||||
self.setStyleSheet(self.theme_manager.get_sheet())
|
self.setStyleSheet(self.theme_manager.get_sheet())
|
||||||
self.setWindowIcon(QIcon(paths.get_asset_path("icon")))
|
self.setWindowIcon(QIcon(paths.get_asset_path("icon")))
|
||||||
|
|
||||||
|
# Apply saved window state
|
||||||
|
self.apply_saved_window_state()
|
||||||
|
|
||||||
self.setup_ui()
|
self.setup_ui()
|
||||||
|
|
||||||
|
def apply_saved_window_state(self):
|
||||||
|
"""Apply saved window size and maximized state"""
|
||||||
|
window_size = self.settings_manager.get_window_size()
|
||||||
|
self.current_size = QSize(window_size["width"], window_size["height"])
|
||||||
|
self.previous_size = self.current_size
|
||||||
|
self.resize(self.current_size)
|
||||||
|
if self.settings_manager.get_maximized():
|
||||||
|
self.showMaximized()
|
||||||
|
|
||||||
|
if hasattr(self, 'current_size'):
|
||||||
|
print(self.current_size)
|
||||||
|
|
||||||
|
def changeEvent(self, event):
|
||||||
|
"""Handle window state changes"""
|
||||||
|
super().changeEvent(event)
|
||||||
|
if event.type() == event.Type.WindowStateChange:
|
||||||
|
# Si on quitte le mode maximisé, sauvegarder la taille actuelle
|
||||||
|
if self.isMaximized():
|
||||||
|
self.current_size = self.previous_size
|
||||||
|
self.settings_manager.set_maximized(self.isMaximized())
|
||||||
|
if hasattr(self, 'current_size'):
|
||||||
|
print(self.current_size)
|
||||||
|
|
||||||
|
def resizeEvent(self, a0):
|
||||||
|
self.previous_size = self.current_size
|
||||||
|
self.current_size = self.size()
|
||||||
|
self.settings_manager.set_window_size(
|
||||||
|
self.current_size.width(),
|
||||||
|
self.current_size.height()
|
||||||
|
)
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
"""Handle application close event"""
|
||||||
|
super().closeEvent(event)
|
||||||
def setup_ui(self):
|
def setup_ui(self):
|
||||||
self.side_menu = TabsWidget(self,MenuDirection.HORIZONTAL,70,None,10,1,BorderSide.TOP)
|
self.side_menu = TabsWidget(self,MenuDirection.HORIZONTAL,70,None,10,1,BorderSide.TOP)
|
||||||
|
|
||||||
self.settings_window = SettingsWindow(self)
|
self.settings_window = SettingsWindow(self)
|
||||||
self.side_menu.add_widget(self.settings_window,"",paths.get_asset_svg_path("settings"), position=ButtonPosition.CENTER)
|
self.side_menu.add_widget(self.settings_window,"",paths.get_asset_svg_path("settings"), position=ButtonPosition.CENTER)
|
||||||
|
|
||||||
|
self.suggestion_window = SuggestionWindow(self)
|
||||||
|
self.side_menu.add_widget(self.suggestion_window,"",paths.get_asset_svg_path("suggestion"), position=ButtonPosition.CENTER)
|
||||||
|
|
||||||
self.setCentralWidget(self.side_menu)
|
self.setCentralWidget(self.side_menu)
|
||||||
|
|
||||||
def update_theme(self):
|
def update_theme(self):
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QComboBox, QLabel, QHBoxLayout, QSizePolicy
|
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QComboBox, QLabel, QHBoxLayout
|
||||||
from PyQt6.QtCore import Qt
|
from PyQt6.QtCore import Qt
|
||||||
from app.core.main_manager import MainManager, NotificationType
|
from app.core.main_manager import MainManager, NotificationType
|
||||||
|
|
||||||
|
146
app/ui/windows/suggestion_window.py
Normal file
146
app/ui/windows/suggestion_window.py
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
from PyQt6.QtWidgets import QWidget, QVBoxLayout, QTextEdit, QPushButton, QLabel, QMessageBox, QHBoxLayout
|
||||||
|
from PyQt6.QtCore import Qt, QThread, pyqtSignal
|
||||||
|
import time
|
||||||
|
import smtplib
|
||||||
|
import os
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
from email.mime.multipart import MIMEMultipart
|
||||||
|
from app.core.main_manager import MainManager, NotificationType
|
||||||
|
|
||||||
|
class EmailSender(QThread):
|
||||||
|
success = pyqtSignal()
|
||||||
|
error = pyqtSignal(str)
|
||||||
|
|
||||||
|
def __init__(self, subject, message):
|
||||||
|
super().__init__()
|
||||||
|
self.subject = subject
|
||||||
|
self.message = message
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
try:
|
||||||
|
# Get email configuration from environment variables
|
||||||
|
password = 'xprqegxuqixgljyi'
|
||||||
|
email = 'louismazindev@gmail.com'
|
||||||
|
smtp_server = 'smtp.gmail.com'
|
||||||
|
smtp_port = 587
|
||||||
|
|
||||||
|
if not password:
|
||||||
|
# Fallback to simulation if no credentials are configured
|
||||||
|
self._simulate_email_sending()
|
||||||
|
return
|
||||||
|
|
||||||
|
# Create message
|
||||||
|
msg = MIMEMultipart()
|
||||||
|
msg['From'] = email
|
||||||
|
msg['To'] = email
|
||||||
|
msg['Subject'] = self.subject
|
||||||
|
|
||||||
|
# Add body to email
|
||||||
|
msg.attach(MIMEText(self.message, 'plain'))
|
||||||
|
|
||||||
|
# Create SMTP session
|
||||||
|
server = smtplib.SMTP(smtp_server, smtp_port)
|
||||||
|
server.starttls() # Enable TLS encryption
|
||||||
|
# Login with app password
|
||||||
|
server.login(email, password)
|
||||||
|
# Send email
|
||||||
|
text = msg.as_string()
|
||||||
|
server.sendmail(email, email, text)
|
||||||
|
server.quit()
|
||||||
|
|
||||||
|
self.success.emit()
|
||||||
|
except Exception as e:
|
||||||
|
self.error.emit()
|
||||||
|
|
||||||
|
def _simulate_email_sending(self):
|
||||||
|
"""Fallback simulation when no email credentials are configured"""
|
||||||
|
time.sleep(2) # Simulate network delay
|
||||||
|
|
||||||
|
print("=== EMAIL SIMULATION (No credentials configured) ===")
|
||||||
|
print(f"Subject: {self.subject}")
|
||||||
|
print(f"Message: {self.message}")
|
||||||
|
print("=" * 55)
|
||||||
|
|
||||||
|
self.success.emit()
|
||||||
|
|
||||||
|
class SuggestionWindow(QWidget):
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.main_manager = MainManager.get_instance()
|
||||||
|
self.language_manager = self.main_manager.get_language_manager()
|
||||||
|
self.settings_manager = self.main_manager.get_settings_manager()
|
||||||
|
|
||||||
|
self.observer_manager = self.main_manager.get_observer_manager()
|
||||||
|
self.observer_manager.subscribe(NotificationType.LANGUAGE, self.update_language)
|
||||||
|
|
||||||
|
self.setup_ui()
|
||||||
|
|
||||||
|
def setup_ui(self):
|
||||||
|
layout = QVBoxLayout(self)
|
||||||
|
layout.setAlignment(Qt.AlignmentFlag.AlignTop)
|
||||||
|
layout.setSpacing(20)
|
||||||
|
layout.setContentsMargins(20, 20, 20, 20)
|
||||||
|
|
||||||
|
# Title
|
||||||
|
self.title_label = QLabel(self.language_manager.get_text("suggestion_text"), self)
|
||||||
|
self.title_label.setStyleSheet("font-size: 18px; font-weight: bold; margin-bottom: 10px;")
|
||||||
|
layout.addWidget(self.title_label)
|
||||||
|
|
||||||
|
# Text area for suggestion
|
||||||
|
self.text_edit = QTextEdit(self)
|
||||||
|
self.text_edit.setPlaceholderText(self.language_manager.get_text("suggestion_placeholder"))
|
||||||
|
self.text_edit.setMinimumHeight(200)
|
||||||
|
layout.addWidget(self.text_edit)
|
||||||
|
|
||||||
|
# Button layout
|
||||||
|
button_layout = QHBoxLayout()
|
||||||
|
button_layout.addStretch()
|
||||||
|
|
||||||
|
# Send button
|
||||||
|
self.send_button = QPushButton(self.language_manager.get_text("send_suggestion"), self)
|
||||||
|
self.send_button.clicked.connect(self.send_suggestion)
|
||||||
|
button_layout.addWidget(self.send_button)
|
||||||
|
|
||||||
|
layout.addLayout(button_layout)
|
||||||
|
layout.addStretch()
|
||||||
|
|
||||||
|
def send_suggestion(self):
|
||||||
|
message = self.text_edit.toPlainText().strip()
|
||||||
|
|
||||||
|
if not message:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Disable send button during sending
|
||||||
|
self.send_button.setEnabled(False)
|
||||||
|
self.send_button.setText(self.language_manager.get_text("sending"))
|
||||||
|
|
||||||
|
# Create subject with app name
|
||||||
|
subject = f"Suggestion for {self.settings_manager.get_config('app_name')}"
|
||||||
|
|
||||||
|
# Create and start email sender thread
|
||||||
|
self.email_sender = EmailSender(subject, message)
|
||||||
|
self.email_sender.success.connect(self.on_email_sent)
|
||||||
|
self.email_sender.error.connect(self.on_email_error)
|
||||||
|
self.email_sender.start()
|
||||||
|
|
||||||
|
def on_email_sent(self):
|
||||||
|
self.send_button.setEnabled(True)
|
||||||
|
self.send_button.setText(self.language_manager.get_text("send_suggestion"))
|
||||||
|
|
||||||
|
QMessageBox.information(self,
|
||||||
|
self.language_manager.get_text("success"),
|
||||||
|
self.language_manager.get_text("suggestion_sent_success"))
|
||||||
|
self.text_edit.clear()
|
||||||
|
|
||||||
|
def on_email_error(self):
|
||||||
|
self.send_button.setEnabled(True)
|
||||||
|
self.send_button.setText(self.language_manager.get_text("send_suggestion"))
|
||||||
|
|
||||||
|
QMessageBox.critical(self,
|
||||||
|
self.language_manager.get_text("error"),
|
||||||
|
f"{self.language_manager.get_text('suggestion_send_error')}")
|
||||||
|
|
||||||
|
def update_language(self):
|
||||||
|
self.title_label.setText(self.language_manager.get_text("suggestion_text"))
|
||||||
|
self.text_edit.setPlaceholderText(self.language_manager.get_text("suggestion_placeholder"))
|
||||||
|
self.send_button.setText(self.language_manager.get_text("send_suggestion"))
|
@ -46,14 +46,3 @@ def get_user_data_dir(app_name: str) -> Path:
|
|||||||
if not path.exists(user_data_path):
|
if not path.exists(user_data_path):
|
||||||
mkdir(user_data_path)
|
mkdir(user_data_path)
|
||||||
return user_data_path
|
return user_data_path
|
||||||
|
|
||||||
def get_current_dir() -> Path:
|
|
||||||
"""
|
|
||||||
Return the directory where the exe or main script is located.
|
|
||||||
"""
|
|
||||||
if getattr(sys, 'frozen', False):
|
|
||||||
# If the application is frozen (PyInstaller)
|
|
||||||
return str(Path(sys.executable).parent)
|
|
||||||
else:
|
|
||||||
# If running in a normal Python environment
|
|
||||||
return str(Path(__file__).parent.parent.parent)
|
|
@ -1 +1 @@
|
|||||||
<ns0:svg xmlns:ns0="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="100px" height="100px" fill="#000000" stroke="#000000"><ns0:path d="M 22.205078 2 A 1.0001 1.0001 0 0 0 21.21875 2.8378906 L 20.246094 8.7929688 C 19.076509 9.1331971 17.961243 9.5922728 16.910156 10.164062 L 11.996094 6.6542969 A 1.0001 1.0001 0 0 0 10.708984 6.7597656 L 6.8183594 10.646484 A 1.0001 1.0001 0 0 0 6.7070312 11.927734 L 10.164062 16.873047 C 9.583454 17.930271 9.1142098 19.051824 8.765625 20.232422 L 2.8359375 21.21875 A 1.0001 1.0001 0 0 0 2.0019531 22.205078 L 2.0019531 27.705078 A 1.0001 1.0001 0 0 0 2.8261719 28.691406 L 8.7597656 29.742188 C 9.1064607 30.920739 9.5727226 32.043065 10.154297 33.101562 L 6.6542969 37.998047 A 1.0001 1.0001 0 0 0 6.7597656 39.285156 L 10.648438 43.175781 A 1.0001 1.0001 0 0 0 11.927734 43.289062 L 16.882812 39.820312 C 17.936999 40.39548 19.054994 40.857928 20.228516 41.201172 L 21.21875 47.164062 A 1.0001 1.0001 0 0 0 22.205078 48 L 27.705078 48 A 1.0001 1.0001 0 0 0 28.691406 47.173828 L 29.751953 41.1875 C 30.920633 40.838997 32.033372 40.369697 33.082031 39.791016 L 38.070312 43.291016 A 1.0001 1.0001 0 0 0 39.351562 43.179688 L 43.240234 39.287109 A 1.0001 1.0001 0 0 0 43.34375 37.996094 L 39.787109 33.058594 C 40.355783 32.014958 40.813915 30.908875 41.154297 29.748047 L 47.171875 28.693359 A 1.0001 1.0001 0 0 0 47.998047 27.707031 L 47.998047 22.207031 A 1.0001 1.0001 0 0 0 47.160156 21.220703 L 41.152344 20.238281 C 40.80968 19.078827 40.350281 17.974723 39.78125 16.931641 L 43.289062 11.933594 A 1.0001 1.0001 0 0 0 43.177734 10.652344 L 39.287109 6.7636719 A 1.0001 1.0001 0 0 0 37.996094 6.6601562 L 33.072266 10.201172 C 32.023186 9.6248101 30.909713 9.1579916 29.738281 8.8125 L 28.691406 2.828125 A 1.0001 1.0001 0 0 0 27.705078 2 L 22.205078 2 z M 23.056641 4 L 26.865234 4 L 27.861328 9.6855469 A 1.0001 1.0001 0 0 0 28.603516 10.484375 C 30.066026 10.848832 31.439607 11.426549 32.693359 12.185547 A 1.0001 1.0001 0 0 0 33.794922 12.142578 L 38.474609 8.7792969 L 41.167969 11.472656 L 37.835938 16.220703 A 1.0001 1.0001 0 0 0 37.796875 17.310547 C 38.548366 18.561471 39.118333 19.926379 39.482422 21.380859 A 1.0001 1.0001 0 0 0 40.291016 22.125 L 45.998047 23.058594 L 45.998047 26.867188 L 40.279297 27.871094 A 1.0001 1.0001 0 0 0 39.482422 28.617188 C 39.122545 30.069817 38.552234 31.434687 37.800781 32.685547 A 1.0001 1.0001 0 0 0 37.845703 33.785156 L 41.224609 38.474609 L 38.53125 41.169922 L 33.791016 37.84375 A 1.0001 1.0001 0 0 0 32.697266 37.808594 C 31.44975 38.567585 30.074755 39.148028 28.617188 39.517578 A 1.0001 1.0001 0 0 0 27.876953 40.3125 L 26.867188 46 L 23.052734 46 L 22.111328 40.337891 A 1.0001 1.0001 0 0 0 21.365234 39.53125 C 19.90185 39.170557 18.522094 38.59371 17.259766 37.835938 A 1.0001 1.0001 0 0 0 16.171875 37.875 L 11.46875 41.169922 L 8.7734375 38.470703 L 12.097656 33.824219 A 1.0001 1.0001 0 0 0 12.138672 32.724609 C 11.372652 31.458855 10.793319 30.079213 10.427734 28.609375 A 1.0001 1.0001 0 0 0 9.6328125 27.867188 L 4.0019531 26.867188 L 4.0019531 23.052734 L 9.6289062 22.117188 A 1.0001 1.0001 0 0 0 10.435547 21.373047 C 10.804273 19.898143 11.383325 18.518729 12.146484 17.255859 A 1.0001 1.0001 0 0 0 12.111328 16.164062 L 8.8261719 11.46875 L 11.523438 8.7734375 L 16.185547 12.105469 A 1.0001 1.0001 0 0 0 17.28125 12.148438 C 18.536908 11.394293 19.919867 10.822081 21.384766 10.462891 A 1.0001 1.0001 0 0 0 22.132812 9.6523438 L 23.056641 4 z M 25 17 C 20.593567 17 17 20.593567 17 25 C 17 29.406433 20.593567 33 25 33 C 29.406433 33 33 29.406433 33 25 C 33 20.593567 29.406433 17 25 17 z M 25 19 C 28.325553 19 31 21.674447 31 25 C 31 28.325553 28.325553 31 25 31 C 21.674447 31 19 28.325553 19 25 C 19 21.674447 21.674447 19 25 19 z" fill="#000000" stroke="#000000" /></ns0:svg>
|
<ns0:svg xmlns:ns0="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="100px" height="100px" fill="#D1D1D6" stroke="#D1D1D6"><ns0:path d="M 22.205078 2 A 1.0001 1.0001 0 0 0 21.21875 2.8378906 L 20.246094 8.7929688 C 19.076509 9.1331971 17.961243 9.5922728 16.910156 10.164062 L 11.996094 6.6542969 A 1.0001 1.0001 0 0 0 10.708984 6.7597656 L 6.8183594 10.646484 A 1.0001 1.0001 0 0 0 6.7070312 11.927734 L 10.164062 16.873047 C 9.583454 17.930271 9.1142098 19.051824 8.765625 20.232422 L 2.8359375 21.21875 A 1.0001 1.0001 0 0 0 2.0019531 22.205078 L 2.0019531 27.705078 A 1.0001 1.0001 0 0 0 2.8261719 28.691406 L 8.7597656 29.742188 C 9.1064607 30.920739 9.5727226 32.043065 10.154297 33.101562 L 6.6542969 37.998047 A 1.0001 1.0001 0 0 0 6.7597656 39.285156 L 10.648438 43.175781 A 1.0001 1.0001 0 0 0 11.927734 43.289062 L 16.882812 39.820312 C 17.936999 40.39548 19.054994 40.857928 20.228516 41.201172 L 21.21875 47.164062 A 1.0001 1.0001 0 0 0 22.205078 48 L 27.705078 48 A 1.0001 1.0001 0 0 0 28.691406 47.173828 L 29.751953 41.1875 C 30.920633 40.838997 32.033372 40.369697 33.082031 39.791016 L 38.070312 43.291016 A 1.0001 1.0001 0 0 0 39.351562 43.179688 L 43.240234 39.287109 A 1.0001 1.0001 0 0 0 43.34375 37.996094 L 39.787109 33.058594 C 40.355783 32.014958 40.813915 30.908875 41.154297 29.748047 L 47.171875 28.693359 A 1.0001 1.0001 0 0 0 47.998047 27.707031 L 47.998047 22.207031 A 1.0001 1.0001 0 0 0 47.160156 21.220703 L 41.152344 20.238281 C 40.80968 19.078827 40.350281 17.974723 39.78125 16.931641 L 43.289062 11.933594 A 1.0001 1.0001 0 0 0 43.177734 10.652344 L 39.287109 6.7636719 A 1.0001 1.0001 0 0 0 37.996094 6.6601562 L 33.072266 10.201172 C 32.023186 9.6248101 30.909713 9.1579916 29.738281 8.8125 L 28.691406 2.828125 A 1.0001 1.0001 0 0 0 27.705078 2 L 22.205078 2 z M 23.056641 4 L 26.865234 4 L 27.861328 9.6855469 A 1.0001 1.0001 0 0 0 28.603516 10.484375 C 30.066026 10.848832 31.439607 11.426549 32.693359 12.185547 A 1.0001 1.0001 0 0 0 33.794922 12.142578 L 38.474609 8.7792969 L 41.167969 11.472656 L 37.835938 16.220703 A 1.0001 1.0001 0 0 0 37.796875 17.310547 C 38.548366 18.561471 39.118333 19.926379 39.482422 21.380859 A 1.0001 1.0001 0 0 0 40.291016 22.125 L 45.998047 23.058594 L 45.998047 26.867188 L 40.279297 27.871094 A 1.0001 1.0001 0 0 0 39.482422 28.617188 C 39.122545 30.069817 38.552234 31.434687 37.800781 32.685547 A 1.0001 1.0001 0 0 0 37.845703 33.785156 L 41.224609 38.474609 L 38.53125 41.169922 L 33.791016 37.84375 A 1.0001 1.0001 0 0 0 32.697266 37.808594 C 31.44975 38.567585 30.074755 39.148028 28.617188 39.517578 A 1.0001 1.0001 0 0 0 27.876953 40.3125 L 26.867188 46 L 23.052734 46 L 22.111328 40.337891 A 1.0001 1.0001 0 0 0 21.365234 39.53125 C 19.90185 39.170557 18.522094 38.59371 17.259766 37.835938 A 1.0001 1.0001 0 0 0 16.171875 37.875 L 11.46875 41.169922 L 8.7734375 38.470703 L 12.097656 33.824219 A 1.0001 1.0001 0 0 0 12.138672 32.724609 C 11.372652 31.458855 10.793319 30.079213 10.427734 28.609375 A 1.0001 1.0001 0 0 0 9.6328125 27.867188 L 4.0019531 26.867188 L 4.0019531 23.052734 L 9.6289062 22.117188 A 1.0001 1.0001 0 0 0 10.435547 21.373047 C 10.804273 19.898143 11.383325 18.518729 12.146484 17.255859 A 1.0001 1.0001 0 0 0 12.111328 16.164062 L 8.8261719 11.46875 L 11.523438 8.7734375 L 16.185547 12.105469 A 1.0001 1.0001 0 0 0 17.28125 12.148438 C 18.536908 11.394293 19.919867 10.822081 21.384766 10.462891 A 1.0001 1.0001 0 0 0 22.132812 9.6523438 L 23.056641 4 z M 25 17 C 20.593567 17 17 20.593567 17 25 C 17 29.406433 20.593567 33 25 33 C 29.406433 33 33 29.406433 33 25 C 33 20.593567 29.406433 17 25 17 z M 25 19 C 28.325553 19 31 21.674447 31 25 C 31 28.325553 28.325553 31 25 31 C 21.674447 31 19 28.325553 19 25 C 19 21.674447 21.674447 19 25 19 z" fill="#D1D1D6" stroke="#D1D1D6" /></ns0:svg>
|
9
data/assets/suggestion.svg
Normal file
9
data/assets/suggestion.svg
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<ns0:svg xmlns:ns0="http://www.w3.org/2000/svg" fill="#4A4A4A" width="800px" height="800px" viewBox="0 0 64 64" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;" version="1.1" xml:space="preserve" stroke="#4A4A4A">
|
||||||
|
|
||||||
|
<ns0:g id="ICON">
|
||||||
|
|
||||||
|
<ns0:path d="M59,43l-54,0l-0,-9c-0,-0.552 -0.448,-1 -1,-1c-0.552,-0 -1,0.448 -1,1c-0,5.651 -0,11.154 -0,14c-0,0.796 0.316,1.559 0.879,2.121c0.562,0.563 1.325,0.879 2.121,0.879l4,0c0.552,0 1,-0.448 1,-1c-0,-0.552 -0.448,-1 -1,-1l-4,0c-0.265,-0 -0.52,-0.105 -0.707,-0.293c-0.188,-0.187 -0.293,-0.442 -0.293,-0.707l-0,-3l54,0l-0,3c0,0.265 -0.105,0.52 -0.293,0.707c-0.187,0.188 -0.442,0.293 -0.707,0.293l-44,0c-0.552,0 -1,0.448 -1,1c0,0.552 0.448,1 1,1l12.606,0c-0.16,2.682 -0.855,6.147 -3.417,8l-1.689,0c-0.552,-0 -1,0.448 -1,1c-0,0.552 0.448,1 1,1l21,0c0.552,-0 1,-0.448 1,-1c-0,-0.552 -0.448,-1 -1,-1l-1.689,0c-2.562,-1.854 -3.257,-5.318 -3.417,-8l20.606,0c0.796,-0 1.559,-0.316 2.121,-0.879c0.563,-0.562 0.879,-1.325 0.879,-2.121c-0,-6.028 -0,-23.972 -0,-30c0,-0.796 -0.316,-1.559 -0.879,-2.121c-0.562,-0.563 -1.325,-0.879 -2.121,-0.879l-11,0c-0.552,0 -1,0.448 -1,1c0,0.552 0.448,1 1,1l11,-0c0.265,0 0.52,0.105 0.707,0.293c0.188,0.187 0.293,0.442 0.293,0.707l-0,25Zm-23.606,8l-6.788,0c-0.155,2.531 -0.785,5.68 -2.585,8l11.958,0c-1.8,-2.32 -2.43,-5.47 -2.585,-8Zm-6.394,-9l6.5,0c0.552,0 1,-0.448 1,-1c0,-0.552 -0.448,-1 -1,-1l-6.5,0c-0.552,0 -1,0.448 -1,1c0,0.552 0.448,1 1,1Zm-22,-4l0,2c0,0.552 0.448,1 1,1c0.552,-0 1,-0.448 1,-1l0,-2c0,-0.552 -0.448,-1 -1,-1c-0.552,-0 -1,0.448 -1,1Zm20.5,1l9.5,0c0.552,-0 1,-0.448 1,-1c-0,-0.552 -0.448,-1 -1,-1l-9.5,0c-0.552,-0 -1,0.448 -1,1c-0,0.552 0.448,1 1,1Zm2.501,-3l-3.406,0c-0.261,0 -0.511,-0.102 -0.698,-0.284c-3.344,-3.257 -6.897,-8.272 -6.897,-14.756c0,-7.152 5.824,-12.96 13,-12.96c7.176,0 13,5.808 13,12.96c-0,6.484 -3.553,11.499 -6.897,14.756c-0.187,0.182 -0.437,0.284 -0.698,0.284l-3.405,0c0,0 -1,-0.003 -1,-1l0,-11l-2,0l0,10.999c0,0.652 -0.447,1.001 -0.999,1.001Zm-21.001,-1l0,-13c0,-0.552 -0.448,-1 -1,-1c-0.552,-0 -1,0.448 -1,1l0,13c0,0.552 0.448,1 1,1c0.552,-0 1,-0.448 1,-1Zm26,-1c0.871,-0 1.995,-0 1.995,-0c2.941,-2.949 6.005,-7.36 6.005,-13.04c0,-6.05 -4.93,-10.96 -11,-10.96c-6.07,0 -11,4.91 -11,10.96c-0,5.68 3.064,10.091 6.005,13.04l1.995,0l0,-10l-2,0c-2.208,0 -4,-1.792 -4,-4c0,-2.208 1.792,-4 4,-4c2.208,0 4,1.792 4,4l0,2l2,0l0,-2c0,-2.208 1.792,-4 4,-4c2.208,0 4,1.792 4,4c0,2.208 -1.792,4 -4,4l-2,0l0,10Zm-18,-19l-11,0c-0.796,0 -1.559,0.316 -2.121,0.879c-0.563,0.562 -0.879,1.325 -0.879,2.121c-0,2.509 -0,7.081 -0,12c-0,0.552 0.448,1 1,1c0.552,0 1,-0.448 1,-1l-0,-12c-0,-0.265 0.105,-0.52 0.293,-0.707c0.187,-0.188 0.442,-0.293 0.707,-0.293c0,0 11,0 11,0c0.552,0 1,-0.448 1,-1c0,-0.552 -0.448,-1 -1,-1Zm18,7l2,0c1.104,0 2,-0.896 2,-2c0,-1.104 -0.896,-2 -2,-2c-1.104,0 -2,0.896 -2,2l0,2Zm-6,0l0,-2c0,-1.104 -0.896,-2 -2,-2c-1.104,0 -2,0.896 -2,2c0,1.104 0.896,2 2,2l2,0Zm-2.509,-14.792l-1,-1.732c-0.276,-0.478 -0.888,-0.642 -1.366,-0.366c-0.478,0.276 -0.642,0.888 -0.366,1.366l1,1.732c0.276,0.478 0.888,0.642 1.366,0.366c0.478,-0.276 0.642,-0.888 0.366,-1.366Zm12.75,1l1,-1.732c0.276,-0.478 0.112,-1.09 -0.366,-1.366c-0.478,-0.276 -1.09,-0.112 -1.366,0.366l-1,1.732c-0.276,0.478 -0.112,1.09 0.366,1.366c0.478,0.276 1.09,0.112 1.366,-0.366Zm-6.241,-2.208l0,-2c0,-0.552 -0.448,-1 -1,-1c-0.552,-0 -1,0.448 -1,1l0,2c0,0.552 0.448,1 1,1c0.552,-0 1,-0.448 1,-1Z" fill="#4A4A4A" stroke="#4A4A4A" />
|
||||||
|
|
||||||
|
</ns0:g>
|
||||||
|
|
||||||
|
</ns0:svg>
|
@ -6,5 +6,13 @@
|
|||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
"theme": "Theme :",
|
"theme": "Theme :",
|
||||||
"dark_theme": "Dark Theme",
|
"dark_theme": "Dark Theme",
|
||||||
"light_theme": "Light Theme"
|
"light_theme": "Light Theme",
|
||||||
|
"suggestion_text": "Do you have a question or an idea to improve this application? Send me a message!",
|
||||||
|
"suggestion_placeholder": "Type your message here...",
|
||||||
|
"send_suggestion": "Send",
|
||||||
|
"sending": "Sending...",
|
||||||
|
"success": "Success",
|
||||||
|
"error": "Error",
|
||||||
|
"suggestion_sent_success": "Your message has been sent successfully!",
|
||||||
|
"suggestion_send_error": "Error sending message. Try again later."
|
||||||
}
|
}
|
@ -6,5 +6,13 @@
|
|||||||
"settings": "Paramètres",
|
"settings": "Paramètres",
|
||||||
"theme": "Thème :",
|
"theme": "Thème :",
|
||||||
"dark_theme": "Thème Sombre",
|
"dark_theme": "Thème Sombre",
|
||||||
"light_theme": "Thème Clair"
|
"light_theme": "Thème Clair",
|
||||||
|
"suggestion_text": "Vous avez une question ou une idée pour améliorer cette application ? Envoyez-moi un message !",
|
||||||
|
"suggestion_placeholder": "Tapez votre message ici...",
|
||||||
|
"send_suggestion": "Envoyer",
|
||||||
|
"sending": "Envoi...",
|
||||||
|
"success": "Succès",
|
||||||
|
"error": "Erreur",
|
||||||
|
"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."
|
||||||
}
|
}
|
@ -2,6 +2,5 @@
|
|||||||
"theme": "dark",
|
"theme": "dark",
|
||||||
"lang": "fr",
|
"lang": "fr",
|
||||||
"window_size": {"width": 1000, "height": 600},
|
"window_size": {"width": 1000, "height": 600},
|
||||||
"fullscreen": true,
|
"maximize": true
|
||||||
"fullscreen_size": {"width": 1000, "height": 600}
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user