Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5b7ef4c951 | |||
| 82679a5709 | |||
| 93c37a905b | |||
| 945abae5f1 | |||
| 720b004eca | |||
| 54aa7a50b2 | |||
| 1125e5ee10 | |||
| 5d2282def1 | |||
| 968d88c18d | |||
| 8a3e487df6 | |||
| 8a87fe38c8 | |||
| 32d8185f66 | |||
| 484809356f | |||
| de8486662e | |||
| 97520e06e5 | |||
| 54a8d5c40f | |||
| 5a6470511a | |||
| e922825481 | |||
| 5b065dddfc | |||
| fd4cf5e51f | |||
| 5cfecdf856 | |||
| c1d3b98949 | |||
| a4ba0e29e8 | |||
| 3af8c97bc5 | |||
| a492a39a8c | |||
| 93e30ee178 | |||
| d877a5cc91 | |||
| 8e22b69f81 | |||
| d0ede2acd5 | |||
| e1b32688b4 | |||
| a6d4a708d8 | |||
| 983d584015 | |||
| 13b591a157 | |||
| 61e4e58ccf | |||
| 83200c4932 | |||
| b2ba3964d3 | |||
| c532fbe137 | |||
| c73756d3d7 | |||
| 6bfcec32ce | |||
| 37e815f42a | |||
| 567901b205 | |||
| 935dbf6253 | |||
| abd1a1073a | |||
| 18c708597a | |||
| 52e4c01f3d | |||
| 75893a8a01 | |||
| cc8aa03102 | |||
| a2e1153340 | |||
| 8c4aa284b7 | |||
| a437de91df | |||
| 42768aa78a | |||
| 8e7242937e | |||
| a4bcd764db | |||
| 8395b2f220 | |||
| b643188418 | |||
| 097524cd27 | |||
| 4be6dd8b84 |
15
.editorconfig
Normal file
@@ -0,0 +1,15 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
indent_size = 2
|
||||
|
||||
[*.py]
|
||||
indent_size = 4
|
||||
|
||||
[pyproject.toml]
|
||||
indent_size = 4
|
||||
403
.gitignore
vendored
Normal file
@@ -0,0 +1,403 @@
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
!*.code-workspace
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[codz]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
# Pipfile.lock
|
||||
|
||||
# UV
|
||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# uv.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
# poetry.lock
|
||||
# poetry.toml
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
||||
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
||||
# pdm.lock
|
||||
# pdm.toml
|
||||
.pdm-python
|
||||
.pdm-build/
|
||||
|
||||
# pixi
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
||||
# pixi.lock
|
||||
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
||||
# in the .venv directory. It is recommended not to include this directory in version control.
|
||||
.pixi
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# Redis
|
||||
*.rdb
|
||||
*.aof
|
||||
*.pid
|
||||
|
||||
# RabbitMQ
|
||||
mnesia/
|
||||
rabbitmq/
|
||||
rabbitmq-data/
|
||||
|
||||
# ActiveMQ
|
||||
activemq-data/
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.envrc
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
# .idea/
|
||||
|
||||
# Abstra
|
||||
# Abstra is an AI-powered process automation framework.
|
||||
# Ignore directories containing user credentials, local state, and settings.
|
||||
# Learn more at https://abstra.io/docs
|
||||
.abstra/
|
||||
|
||||
# Visual Studio Code
|
||||
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
||||
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
||||
# you could uncomment the following to ignore the entire vscode folder
|
||||
# .vscode/
|
||||
|
||||
# Ruff stuff:
|
||||
.ruff_cache/
|
||||
|
||||
# PyPI configuration file
|
||||
.pypirc
|
||||
|
||||
# Marimo
|
||||
marimo/_static/
|
||||
marimo/_lsp/
|
||||
__marimo__/
|
||||
|
||||
# Streamlit
|
||||
.streamlit/secrets.toml
|
||||
|
||||
# Covers JetBrains IDEs: IntelliJ, GoLand, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
.idea/sonarlint.xml # see https://community.sonarsource.com/t/is-the-file-idea-idea-idea-sonarlint-xml-intended-to-be-under-source-control/121119
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based HTTP Client
|
||||
.idea/httpRequests
|
||||
http-client.private.env.json
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
# Apifox Helper cache
|
||||
.idea/.cache/.Apifox_Helper
|
||||
.idea/ApifoxUploaderProjectSetting.xml
|
||||
|
||||
# Github Copilot persisted session migrations, see: https://github.com/microsoft/copilot-intellij-feedback/issues/712#issuecomment-3322062215
|
||||
.idea/**/copilot.data.migration.*.xml
|
||||
|
||||
# Covers JetBrains IDEs: IntelliJ, GoLand, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
.idea/sonarlint.xml # see https://community.sonarsource.com/t/is-the-file-idea-idea-idea-sonarlint-xml-intended-to-be-under-source-control/121119
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based HTTP Client
|
||||
.idea/httpRequests
|
||||
http-client.private.env.json
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
# Apifox Helper cache
|
||||
.idea/.cache/.Apifox_Helper
|
||||
.idea/ApifoxUploaderProjectSetting.xml
|
||||
|
||||
# Github Copilot persisted session migrations, see: https://github.com/microsoft/copilot-intellij-feedback/issues/712#issuecomment-3322062215
|
||||
.idea/**/copilot.data.migration.*.xml
|
||||
src/config.json
|
||||
config.json
|
||||
10
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Ignored default folder with query files
|
||||
/queries/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
11
.idea/PyQt6_LaTaniere.iml
generated
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="uv (PyQt6_LaTaniere)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
7
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="uv (PyQt6_LaTaniere)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="uv (PyQt6_LaTaniere)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/PyQt6_LaTaniere.iml" filepath="$PROJECT_DIR$/.idea/PyQt6_LaTaniere.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
19
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"ms-python.python",
|
||||
"ms-python.debugpy",
|
||||
"ms-python.vscode-pylance",
|
||||
"ms-python.vscode-python-envs",
|
||||
"ms-python.mypy-type-checker",
|
||||
"charliermarsh.ruff",
|
||||
"editorconfig.editorconfig",
|
||||
"njpwerner.autodocstring",
|
||||
"redhat.vscode-yaml",
|
||||
"tamasfe.even-better-toml",
|
||||
"codezombiech.gitignore",
|
||||
"theqtcompany.qt-core",
|
||||
"theqtcompany.qt-ui",
|
||||
"theqtcompany.qt-python",
|
||||
"theqtcompany.qt-qml",
|
||||
]
|
||||
}
|
||||
30
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Python Debugger: Attach using Process Id",
|
||||
"type": "debugpy",
|
||||
"request": "attach",
|
||||
"processId": "${command:pickProcess}"
|
||||
},
|
||||
{
|
||||
"name": "Python Debugger: Current File",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "${file}",
|
||||
"console": "integratedTerminal"
|
||||
},
|
||||
{
|
||||
"name": "Python Debugger: Attach",
|
||||
"type": "debugpy",
|
||||
"request": "attach",
|
||||
"connect": {
|
||||
"host": "localhost",
|
||||
"port": 5678
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
26
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"python.analysis.autoImportCompletions": true,
|
||||
"python.analysis.extraPaths": [".venv/lib/site-packages"],
|
||||
"python.analysis.fixAll": ["source.unusedImports"],
|
||||
"python.languageServer": "Pylance",
|
||||
"mypy-type-checker.args": [
|
||||
"--disallow-untyped-defs=True",
|
||||
"--disallow-untyped-calls=True",
|
||||
"--check-untyped-defs=True",
|
||||
"--warn_return_any=True",
|
||||
"--no-implicit-optional=True",
|
||||
"--strict_optional=True",
|
||||
"--ignore_missing_imports=True",
|
||||
],
|
||||
"editor.defaultFormatter": "charliermarsh.ruff",
|
||||
"python.useEnvironmentsExtension": true,
|
||||
"terminal.integrated.persistentSessionReviveProcess": "never",
|
||||
"terminal.integrated.enablePersistentSessions": false,
|
||||
"terminal.integrated.hideOnStartup": "always",
|
||||
"[jsonc]": {
|
||||
"editor.defaultFormatter": "vscode.json-language-features"
|
||||
},
|
||||
"files.exclude": {
|
||||
"**/__pycache__": true
|
||||
}
|
||||
}
|
||||
266
La Tanière Launcher.spec
Normal file
@@ -0,0 +1,266 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
a = Analysis(
|
||||
['src\\main.py'],
|
||||
pathex=['src'],
|
||||
binaries=[],
|
||||
datas=[
|
||||
('.\\styles\\styles.qss', 'styles'),
|
||||
('.\\ui\\mainwindow_vertical_pager.ui', 'ui')
|
||||
],
|
||||
hiddenimports=[
|
||||
"asyncio",
|
||||
"pypresence",
|
||||
"pypresence.baseclient",
|
||||
],
|
||||
hookspath=[],
|
||||
hooksconfig={
|
||||
"qt_plugins": ["platforms", "styles"]
|
||||
},
|
||||
runtime_hooks=[],
|
||||
excludes=[
|
||||
# PySide6 - modules non utilisés
|
||||
'PySide6.Qt3DAnimation',
|
||||
'PySide6.Qt3DCore',
|
||||
'PySide6.Qt3DExtras',
|
||||
'PySide6.Qt3DInput',
|
||||
'PySide6.Qt3DLogic',
|
||||
'PySide6.Qt3DRender',
|
||||
'PySide6.QtAxContainer',
|
||||
'PySide6.QtBluetooth',
|
||||
'PySide6.QtCharts',
|
||||
'PySide6.QtConcurrent',
|
||||
'PySide6.QtDataVisualization',
|
||||
'PySide6.QtDesigner',
|
||||
'PySide6.QtHelp',
|
||||
'PySide6.QtLocation',
|
||||
# 'PySide6.QtMultimedia', # Nécessaire pour l'audio
|
||||
'PySide6.QtMultimediaWidgets',
|
||||
# 'PySide6.QtNetwork', # Dépendance à QtMultimedia
|
||||
'PySide6.QtNetworkAuth',
|
||||
'PySide6.QtNfc',
|
||||
'PySide6.QtOpenGL',
|
||||
'PySide6.QtOpenGLWidgets',
|
||||
'PySide6.QtPdf',
|
||||
'PySide6.QtPdfWidgets',
|
||||
'PySide6.QtPositioning',
|
||||
'PySide6.QtPrintSupport',
|
||||
'PySide6.QtQml',
|
||||
'PySide6.QtQuick',
|
||||
'PySide6.QtQuick3D',
|
||||
'PySide6.QtQuickControls2',
|
||||
'PySide6.QtQuickWidgets',
|
||||
'PySide6.QtRemoteObjects',
|
||||
'PySide6.QtScxml',
|
||||
'PySide6.QtSensors',
|
||||
'PySide6.QtSerialBus',
|
||||
'PySide6.QtSerialPort',
|
||||
'PySide6.QtSpatialAudio',
|
||||
'PySide6.QtSql',
|
||||
'PySide6.QtStateMachine',
|
||||
'PySide6.QtSvg',
|
||||
'PySide6.QtSvgWidgets',
|
||||
'PySide6.QtTest',
|
||||
'PySide6.QtTextToSpeech',
|
||||
'PySide6.QtWebChannel',
|
||||
'PySide6.QtWebEngineCore',
|
||||
'PySide6.QtWebEngineQuick',
|
||||
'PySide6.QtWebEngineWidgets',
|
||||
'PySide6.QtWebSockets',
|
||||
'PySide6.QtXml',
|
||||
|
||||
# Tests / dev tools
|
||||
"test",
|
||||
"tests",
|
||||
"unittest",
|
||||
"doctest",
|
||||
"pydoc",
|
||||
"pydoc_data",
|
||||
|
||||
# Packaging / build tooling
|
||||
"distutils",
|
||||
"setuptools",
|
||||
"pkg_resources",
|
||||
"pip",
|
||||
"ensurepip",
|
||||
|
||||
# GUI stdlib inutiles
|
||||
"tkinter",
|
||||
"turtle",
|
||||
"idlelib",
|
||||
"curses",
|
||||
|
||||
# Legacy / obsolete
|
||||
"lib2to3",
|
||||
"2to3",
|
||||
"nis",
|
||||
"ossaudiodev",
|
||||
"spwd",
|
||||
|
||||
# RPC / servers non utilisés
|
||||
"xmlrpc",
|
||||
"wsgiref",
|
||||
"cgi",
|
||||
"cgitb",
|
||||
|
||||
# Data / DB non utilisés
|
||||
"sqlite3",
|
||||
"dbm",
|
||||
"dbm.dumb",
|
||||
"csv",
|
||||
|
||||
# Concurrency non utilisée dans ton code
|
||||
"multiprocessing",
|
||||
#"concurrent",
|
||||
#"asyncio",
|
||||
|
||||
# REPL / terminal
|
||||
"readline",
|
||||
"code",
|
||||
# "codeop", # Nécessaire
|
||||
"cmd",
|
||||
|
||||
# mail / network protocols non utilisés
|
||||
"mailbox",
|
||||
"imaplib",
|
||||
"poplib",
|
||||
"smtplib",
|
||||
"nntplib",
|
||||
"telnetlib",
|
||||
"ftplib",
|
||||
"netrc",
|
||||
|
||||
# Docs / browsing / parsing non utilisés directement
|
||||
"pydoc_data",
|
||||
"mailbox",
|
||||
"imaplib",
|
||||
"poplib",
|
||||
"smtplib",
|
||||
"nntplib",
|
||||
"telnetlib",
|
||||
|
||||
# XML optionnel : agressif mais plutôt safe ici
|
||||
"xml.dom",
|
||||
"xml.etree",
|
||||
"xml.parsers",
|
||||
"xml.sax",
|
||||
|
||||
# Compression / archive optionnelles si non utilisées
|
||||
"bz2",
|
||||
"lzma",
|
||||
"gzip",
|
||||
#"zipfile", # Nécessaire à cause de pyinstaller
|
||||
"tarfile",
|
||||
"zipapp",
|
||||
|
||||
# audio stdlib non utilisée
|
||||
"aifc",
|
||||
"wave",
|
||||
"sunau",
|
||||
"chunk",
|
||||
|
||||
# divers peu probables
|
||||
"mailcap",
|
||||
"xdrlib",
|
||||
"tabnanny",
|
||||
"getpass",
|
||||
|
||||
# Windows services non utilisés
|
||||
"win32service",
|
||||
"win32serviceutil",
|
||||
],
|
||||
noarchive=False,
|
||||
optimize=2,
|
||||
)
|
||||
|
||||
# --- Filtre des DLLs Qt inutiles ---
|
||||
# Ces DLLs sont incluses par analyse binaire malgré les excludes Python
|
||||
unwanted_dlls = [
|
||||
'Qt6Pdf',
|
||||
'Qt6Quick',
|
||||
'Qt6Qml',
|
||||
'Qt6QmlModels',
|
||||
'Qt6QmlWorkerScript',
|
||||
'Qt6WebEngine',
|
||||
'Qt6WebEngineCore',
|
||||
'Qt63DCore',
|
||||
'Qt63DRender',
|
||||
'Qt63DAnimation',
|
||||
'Qt63DExtras',
|
||||
'Qt63DInput',
|
||||
'Qt63DLogic',
|
||||
'Qt6Charts',
|
||||
'Qt6DataVisualization',
|
||||
'Qt6Bluetooth',
|
||||
'Qt6Nfc',
|
||||
'Qt6Positioning',
|
||||
'Qt6Location',
|
||||
'Qt6RemoteObjects',
|
||||
'Qt6Scxml',
|
||||
'Qt6Sensors',
|
||||
'Qt6SerialBus',
|
||||
'Qt6SerialPort',
|
||||
'Qt6SpatialAudio',
|
||||
'Qt6StateMachine',
|
||||
# 'Qt6Svg', # Dependance lecteur svg
|
||||
'Qt6TextToSpeech',
|
||||
'Qt6WebChannel',
|
||||
'Qt6WebSockets',
|
||||
'Qt6Sql',
|
||||
'Qt6Test',
|
||||
# 'Qt6OpenGL', # Dependance a Qt6UiTools
|
||||
'Qt6PrintSupport',
|
||||
# 'Qt6Xml', # Dependance fichier .ui
|
||||
'Qt6Help',
|
||||
'Qt6Designer',
|
||||
'Qt6Concurrent',
|
||||
]
|
||||
|
||||
a.binaries = [
|
||||
(name, path, typecode)
|
||||
for name, path, typecode in a.binaries
|
||||
if not any(u.lower() in name.lower() for u in unwanted_dlls)
|
||||
]
|
||||
|
||||
# AJOUTE CECI ICI :
|
||||
# On filtre la liste des fichiers de données (datas)
|
||||
# On exclut tout ce qui se trouve dans le dossier 'translations' de PySide6
|
||||
a.datas = [f for f in a.datas if "translations" not in f[0].lower()]
|
||||
|
||||
# Si tu veux aussi supprimer les traductions système de Qt (fichiers .qm)
|
||||
a.datas = [f for f in a.datas if not f[0].endswith('.qm')]
|
||||
|
||||
|
||||
pyz = PYZ(a.pure, a.zipped_data)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='La Tanière Launcher',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[
|
||||
"_uuid.pyd",
|
||||
"Qt6Core.dll",
|
||||
"Qt6Gui.dll",
|
||||
"Qt6Widgets.dll",
|
||||
"Qt6UiTools.dll",
|
||||
"qwindows.dll",
|
||||
"python3*.dll",
|
||||
"vcruntime*.dll",
|
||||
"msvcp*.dll",
|
||||
],
|
||||
runtime_tmpdir=None,
|
||||
console=False,
|
||||
disable_windowed_traceback=True,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon=['assets\\Icon.ico'],
|
||||
)
|
||||
BIN
assets/Icon.ico
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
assets/Icone.ico
|
Before Width: | Height: | Size: 109 KiB |
BIN
assets/Logo_rond.png
Normal file
|
After Width: | Height: | Size: 222 KiB |
23
assets/closed-store-info.svg
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" ?>
|
||||
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 120 120" id="Layer_1" version="1.1" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
|
||||
<style type="text/css">
|
||||
.st0{fill:#FF5462;}
|
||||
.st1{opacity:0.1;}
|
||||
.st2{fill:#C44151;}
|
||||
.st3{fill:#FFFFFF;}
|
||||
</style>
|
||||
|
||||
<g>
|
||||
|
||||
<path class="st0" d="M100.4,97.2H19.6c-2.3,0-4.1-1.8-4.1-4.1V57.5c0-2.3,1.8-4.1,4.1-4.1h80.7c2.3,0,4.1,1.8,4.1,4.1v35.6 C104.5,95.3,102.6,97.2,100.4,97.2z"/>
|
||||
|
||||
<path class="st1" d="M102.5,96.2h-80c-2.5,0-4.5-2-4.5-4.5V56.8c0-1.4,0.7-2.6,1.7-3.5c-2.3,0.1-4.2,2.1-4.2,4.5v34.9 c0,2.5,2,4.5,4.5,4.5h80c1.1,0,2.1-0.4,2.8-1C102.7,96.2,102.6,96.2,102.5,96.2z"/>
|
||||
|
||||
<path class="st2" d="M57,33.5L37.1,53.4h4.6L60,35.1l18.3,18.3h4.6L63,33.5c1.6-1,2.8-2.8,2.8-4.9c0-3.2-2.6-5.8-5.8-5.8 c-3.2,0-5.8,2.6-5.8,5.8C54.2,30.7,55.3,32.5,57,33.5z M60,26.1c1.4,0,2.5,1.1,2.5,2.5s-1.1,2.5-2.5,2.5c-1.4,0-2.5-1.1-2.5-2.5 S58.6,26.1,60,26.1z"/>
|
||||
|
||||
<g>
|
||||
|
||||
<path class="st3" d="M28.9,73c0.2-0.3,0.5-0.5,0.9-0.6c0.3-0.1,0.7-0.2,1.1-0.2c0.5,0,1,0.1,1.4,0.4c0.4,0.3,0.8,0.6,1.1,1.1 l2.5-2.4c-0.6-0.8-1.3-1.4-2.2-1.9c-0.9-0.4-1.9-0.7-3-0.7c-0.9,0-1.8,0.2-2.6,0.5c-0.8,0.3-1.5,0.8-2.1,1.4 c-0.6,0.6-1,1.3-1.4,2.1c-0.3,0.8-0.5,1.7-0.5,2.7c0,1,0.2,1.9,0.5,2.7c0.3,0.8,0.8,1.5,1.4,2.1c0.6,0.6,1.3,1,2.1,1.4 c0.8,0.3,1.7,0.5,2.6,0.5c1.1,0,2.2-0.2,3-0.7c0.9-0.4,1.6-1.1,2.2-1.9L33.5,77c-0.3,0.5-0.7,0.8-1.1,1.1 c-0.4,0.3-0.9,0.4-1.4,0.4c-0.4,0-0.8-0.1-1.1-0.2c-0.3-0.1-0.6-0.4-0.9-0.6c-0.2-0.3-0.4-0.6-0.6-1c-0.1-0.4-0.2-0.8-0.2-1.3 c0-0.5,0.1-0.9,0.2-1.3C28.5,73.6,28.7,73.2,28.9,73z"/>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
23
assets/computer-tv.svg
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 501.333 501.333" xml:space="preserve">
|
||||
<path style="fill:#637888;" d="M458.667,241.067c0,11.733-8.533,21.333-20.267,21.333H62.933c-10.667,0-20.267-9.6-20.267-21.333
|
||||
V21.333C42.667,9.6,51.2,0,62.933,0H438.4c10.667,0,20.267,9.6,20.267,21.333L458.667,241.067L458.667,241.067z"/>
|
||||
<path style="fill:#53C2EF;" d="M62.933,249.6c-5.333,0-8.533-4.267-8.533-9.6V21.333c0-5.333,4.267-9.6,8.533-9.6H438.4
|
||||
c5.333,0,8.533,4.267,8.533,9.6v219.733c0,5.333-4.267,9.6-8.533,9.6H62.933V249.6z"/>
|
||||
<rect x="166.4" y="262.4" style="fill:#3A5569;" width="168.533" height="61.867"/>
|
||||
<path style="fill:#637888;" d="M363.733,317.867H137.6c-18.133,0-34.133,10.667-34.133,23.467h294.4
|
||||
C397.867,328.533,382.933,317.867,363.733,317.867z"/>
|
||||
<rect y="342.4" style="fill:#3A5569;" width="501.333" height="158.933"/>
|
||||
<g>
|
||||
<rect x="268.8" y="375.467" style="fill:#637888;" width="194.133" height="45.867"/>
|
||||
<rect x="28.8" y="364.8" style="fill:#637888;" width="11.733" height="113.067"/>
|
||||
<rect x="60.8" y="364.8" style="fill:#637888;" width="11.733" height="113.067"/>
|
||||
<rect x="91.733" y="364.8" style="fill:#637888;" width="11.733" height="113.067"/>
|
||||
<rect x="122.667" y="364.8" style="fill:#637888;" width="11.733" height="113.067"/>
|
||||
<rect x="153.6" y="364.8" style="fill:#637888;" width="11.733" height="113.067"/>
|
||||
</g>
|
||||
<circle style="fill:#F16D6E;" cx="225.067" cy="400" r="11.733"/>
|
||||
<circle style="fill:#60C3AB;" cx="225.067" cy="443.733" r="11.733"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
8
assets/discord-icon.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 -28.5 256 256" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||
<g>
|
||||
<path d="M216.856339,16.5966031 C200.285002,8.84328665 182.566144,3.2084988 164.041564,0 C161.766523,4.11318106 159.108624,9.64549908 157.276099,14.0464379 C137.583995,11.0849896 118.072967,11.0849896 98.7430163,14.0464379 C96.9108417,9.64549908 94.1925838,4.11318106 91.8971895,0 C73.3526068,3.2084988 55.6133949,8.86399117 39.0420583,16.6376612 C5.61752293,67.146514 -3.4433191,116.400813 1.08711069,164.955721 C23.2560196,181.510915 44.7403634,191.567697 65.8621325,198.148576 C71.0772151,190.971126 75.7283628,183.341335 79.7352139,175.300261 C72.104019,172.400575 64.7949724,168.822202 57.8887866,164.667963 C59.7209612,163.310589 61.5131304,161.891452 63.2445898,160.431257 C105.36741,180.133187 151.134928,180.133187 192.754523,160.431257 C194.506336,161.891452 196.298154,163.310589 198.110326,164.667963 C191.183787,168.842556 183.854737,172.420929 176.223542,175.320965 C180.230393,183.341335 184.861538,190.991831 190.096624,198.16893 C211.238746,191.588051 232.743023,181.531619 254.911949,164.955721 C260.227747,108.668201 245.831087,59.8662432 216.856339,16.5966031 Z M85.4738752,135.09489 C72.8290281,135.09489 62.4592217,123.290155 62.4592217,108.914901 C62.4592217,94.5396472 72.607595,82.7145587 85.4738752,82.7145587 C98.3405064,82.7145587 108.709962,94.5189427 108.488529,108.914901 C108.508531,123.290155 98.3405064,135.09489 85.4738752,135.09489 Z M170.525237,135.09489 C157.88039,135.09489 147.510584,123.290155 147.510584,108.914901 C147.510584,94.5396472 157.658606,82.7145587 170.525237,82.7145587 C183.391518,82.7145587 193.761324,94.5189427 193.539891,108.914901 C193.539891,123.290155 183.391518,135.09489 170.525237,135.09489 Z" fill="#5865F2" fill-rule="nonzero">
|
||||
|
||||
</path>
|
||||
</g>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
11
assets/letter-i-info.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 512 512" xml:space="preserve">
|
||||
<g>
|
||||
<circle style="fill:#FFD24D;" cx="255.999" cy="75.469" r="75.469"/>
|
||||
<path style="fill:#FFD24D;" d="M359.345,230.952v-45.874H152.654v45.874c15.395,0,27.874,12.479,27.874,27.873v179.426
|
||||
c0,15.394-12.48,27.874-27.874,27.874V512h206.692v-45.873c-15.395,0-27.874-12.48-27.874-27.874V258.825
|
||||
C331.471,243.431,343.951,230.952,359.345,230.952z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 671 B |
BIN
assets/logo.png
Normal file
|
After Width: | Height: | Size: 140 KiB |
21
assets/open-store-info.svg
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" ?>
|
||||
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg width="800px" height="800px" viewBox="0 0 120 120" id="Layer_1" version="1.1" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
|
||||
<style type="text/css">
|
||||
.st0{fill:#00CB72;}
|
||||
.st1{opacity:0.1;}
|
||||
.st2{fill:#009A64;}
|
||||
.st3{fill:#FFFFFF;}
|
||||
</style>
|
||||
|
||||
<g>
|
||||
|
||||
<path class="st0" d="M100.4,97.2H19.6c-2.3,0-4.1-1.8-4.1-4.1V57.5c0-2.3,1.8-4.1,4.1-4.1h80.7c2.3,0,4.1,1.8,4.1,4.1v35.6 C104.5,95.3,102.6,97.2,100.4,97.2z"/>
|
||||
|
||||
<path class="st1" d="M102.5,96.2h-80c-2.5,0-4.5-2-4.5-4.5V56.8c0-1.4,0.7-2.6,1.7-3.5c-2.3,0.1-4.2,2.1-4.2,4.5v34.9 c0,2.5,2,4.5,4.5,4.5h80c1.1,0,2.1-0.4,2.8-1C102.7,96.2,102.6,96.2,102.5,96.2z"/>
|
||||
|
||||
<path class="st2" d="M57,33.5L37.1,53.4h4.6L60,35.1l18.3,18.3h4.6L63,33.5c1.6-1,2.8-2.8,2.8-4.9c0-3.2-2.6-5.8-5.8-5.8 c-3.2,0-5.8,2.6-5.8,5.8C54.2,30.7,55.3,32.5,57,33.5z M60,26.1c1.4,0,2.5,1.1,2.5,2.5s-1.1,2.5-2.5,2.5c-1.4,0-2.5-1.1-2.5-2.5 S58.6,26.1,60,26.1z"/>
|
||||
|
||||
<g>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
14
assets/padlock-lock.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 512.001 512.001" xml:space="preserve">
|
||||
<path style="fill:#FF9E16;" d="M459.897,231.945c0-16.19-13.246-29.436-29.436-29.436H81.54c-16.19,0-29.436,13.247-29.436,29.436
|
||||
v250.619C52.104,498.754,65.349,512,81.54,512H430.46c16.189,0,29.436-13.246,29.436-29.436V231.945H459.897z"/>
|
||||
<path style="fill:#0071CE;" d="M52.104,458.106v24.459c0,16.189,13.245,29.436,29.436,29.436H430.46
|
||||
c16.189,0,29.436-13.246,29.436-29.436v-24.459H52.104z"/>
|
||||
<path style="fill:#0055B8;" d="M284.42,344.612c14.456-9.34,24.033-25.585,24.033-44.077c0-28.969-23.484-52.453-52.453-52.453
|
||||
s-52.453,23.484-52.453,52.453c0,18.491,9.578,34.736,24.034,44.077l-9.012,61.623c-0.809,5.538,3.107,10.069,8.703,10.069h57.457
|
||||
c5.597,0,9.513-4.531,8.703-10.069L284.42,344.612z"/>
|
||||
<path style="fill:#333E48;" d="M384.933,202.51h-52.985v-73.576c0-41.878-34.069-75.948-75.948-75.948s-75.949,34.069-75.949,75.948
|
||||
v73.576h-52.985v-73.576C127.067,57.839,184.907,0,256.001,0s128.933,57.839,128.933,128.933L384.933,202.51L384.933,202.51z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
30
assets/sound-speaker.svg
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 512 512" xml:space="preserve">
|
||||
<path style="fill:#4A5058;" d="M144.24,167.708H29.247c-11.636,0-21.069,9.433-21.069,21.067v134.448
|
||||
c0,11.636,9.433,21.067,21.069,21.067H144.24V167.708z"/>
|
||||
<rect x="62.112" y="167.704" style="fill:#E45D4C;" width="28.195" height="176.582"/>
|
||||
<path style="fill:#7E858B;" d="M297.578,62.32L144.24,167.708v176.583L297.578,449.68c7.783,5.349,18.374-0.222,18.374-9.666V71.986
|
||||
C315.952,62.542,305.361,56.97,297.578,62.32z"/>
|
||||
<path style="opacity:0.2;enable-background:new ;" d="M311.097,436.161L162.493,334.026c-3.083-2.119-6.738-3.253-10.479-3.253
|
||||
H42.765c-11.636,0-21.067-9.433-21.067-21.067V175.258c0-2.274,0.371-4.46,1.037-6.512c-8.446,2.745-14.555,10.669-14.555,20.03
|
||||
v134.448c0,11.636,9.433,21.067,21.069,21.067h114.992L297.579,449.68c7.783,5.349,18.374-0.222,18.374-9.666v-1.91
|
||||
C314.293,437.846,312.64,437.222,311.097,436.161z"/>
|
||||
<path d="M429.806,79.937c-3.457-2.908-8.618-2.46-11.523,0.999c-2.906,3.458-2.459,8.617,0.999,11.523
|
||||
c48.528,40.785,76.361,100.396,76.361,163.546c0,63.149-27.833,122.76-76.361,163.545c-3.458,2.907-3.905,8.066-0.999,11.523
|
||||
c1.617,1.926,3.933,2.917,6.266,2.917c1.857,0,3.726-0.629,5.258-1.918C482.041,388.171,512,323.996,512,256.004
|
||||
C512,188.012,482.041,123.837,429.806,79.937z M393.581,123.107c-3.457-2.906-8.617-2.462-11.523,0.999
|
||||
c-2.906,3.458-2.459,8.617,0.999,11.523c35.719,30.021,56.205,73.897,56.205,120.375s-20.486,90.353-56.205,120.374
|
||||
c-3.458,2.906-3.905,8.066-0.999,11.523c1.617,1.926,3.934,2.917,6.266,2.917c1.857,0,3.726-0.629,5.258-1.918
|
||||
c39.427-33.137,62.04-81.576,62.04-132.896S433.008,156.246,393.581,123.107z M313.492,54.367
|
||||
c-6.567-3.454-14.438-2.987-20.547,1.212L141.7,159.529H29.247C13.12,159.528,0,172.649,0,188.776v134.448
|
||||
c0,16.127,13.12,29.247,29.247,29.247H141.7l151.246,103.95c3.39,2.331,7.321,3.511,11.272,3.511c3.17,0,6.353-0.76,9.276-2.298
|
||||
c6.562-3.453,10.639-10.205,10.639-17.619V71.986C324.131,64.571,320.055,57.82,313.492,54.367z M136.061,336.113H29.247
|
||||
c-7.106,0-12.888-5.781-12.888-12.888V188.776c0-7.108,5.782-12.888,12.888-12.888H136.06v160.225H136.061z M307.772,440.014
|
||||
c0,1.865-1.189,2.769-1.897,3.142c-0.709,0.371-2.126,0.841-3.663-0.216L152.42,339.989V172.011L302.212,69.06
|
||||
c1.539-1.057,2.956-0.586,3.663-0.216c0.709,0.373,1.897,1.277,1.897,3.142V440.014z M357.385,166.238
|
||||
c-3.461-2.904-8.619-2.455-11.525,1.002c-2.905,3.459-2.456,8.619,1.002,11.525c22.889,19.225,36.017,47.379,36.017,77.24
|
||||
s-13.128,58.013-36.017,77.239c-3.458,2.905-3.908,8.066-1.002,11.525c1.618,1.926,3.935,2.918,6.268,2.918
|
||||
c1.856,0,3.723-0.628,5.257-1.916c26.599-22.342,41.854-55.06,41.854-89.766C399.239,221.299,383.984,188.581,357.385,166.238z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
BIN
assets/the-beat-of-nature.mp3
Normal file
36
assets/tools-repair.svg
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 512 512" xml:space="preserve">
|
||||
<rect x="224.236" y="84.672" transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 251.8026 619.7746)" style="fill:#D7D5D9;" width="60.049" height="346.13"/>
|
||||
<path style="fill:#FF3F62;" d="M301.182,253.278l-47.095,47.095c-8.99,8.99-8.99,23.701,0,32.692l153.555,153.555
|
||||
c8.99,8.99,23.702,8.99,32.692,0l47.095-47.095c8.99-8.99,8.99-23.701,0-32.692L333.874,253.278
|
||||
C324.884,244.288,310.173,244.288,301.182,253.278z"/>
|
||||
<polygon style="fill:#D7D5D9;" points="82.211,19.389 20.989,80.611 57.004,116.626 72.013,101.618 227.017,257.43 257.431,227.017
|
||||
102.427,71.203 118.226,55.404 "/>
|
||||
<g>
|
||||
|
||||
<rect x="327.715" y="127.531" transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 501.6223 516.2964)" style="opacity:0.3;fill:#3E3B43;enable-background:new ;" width="60.049" height="53.456"/>
|
||||
|
||||
<rect x="129.012" y="331.181" transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 21.903 715.0185)" style="opacity:0.3;fill:#3E3B43;enable-background:new ;" width="60.049" height="43.584"/>
|
||||
</g>
|
||||
<g>
|
||||
<path style="fill:#77757E;" d="M488.276,74.56l-50.32,50.32l-50.837-50.835l50.32-50.32l-12.132-12.132
|
||||
c-15.457-15.457-40.519-15.457-55.976,0l-44.664,44.664c-15.457,15.457-15.457,40.519,0,55.976l75.099,75.099
|
||||
c15.457,15.457,40.519,15.457,55.976,0l44.665-44.665c15.457-15.457,15.457-40.519,0-55.976L488.276,74.56z"/>
|
||||
<path style="fill:#77757E;" d="M23.725,437.439l50.32-50.32l50.836,50.836l-50.32,50.32l12.132,12.132
|
||||
c15.457,15.457,40.519,15.457,55.976,0l44.665-44.665c15.457-15.457,15.457-40.519,0-55.976l-75.099-75.099
|
||||
c-15.457-15.457-40.519-15.457-55.976,0l-44.665,44.665c-15.457,15.457-15.457,40.519,0,55.976L23.725,437.439z"/>
|
||||
</g>
|
||||
<path style="fill:#C70024;" d="M301.182,253.278l-47.095,47.095c-8.99,8.99-8.99,23.701,0,32.692l16.919,16.919l79.787-79.787
|
||||
l-16.919-16.919C324.884,244.288,310.173,244.288,301.182,253.278z"/>
|
||||
<g>
|
||||
|
||||
<rect x="207.016" y="220.106" transform="matrix(-0.7071 0.7071 -0.7071 -0.7071 551.4321 228.509)" style="opacity:0.3;fill:#3E3B43;enable-background:new ;" width="42.748" height="16.708"/>
|
||||
|
||||
<rect x="21.519" y="44.57" transform="matrix(-0.7071 0.7071 -0.7071 -0.7071 155.3011 62.1083)" style="opacity:0.07;fill:#3E3B43;enable-background:new ;" width="86.538" height="37.297"/>
|
||||
</g>
|
||||
<path style="fill:#FF728B;" d="M427.612,441.54L322.604,336.532c-4.069-4.069-4.069-10.668,0-14.738l0,0
|
||||
c4.069-4.069,10.668-4.069,14.738,0L442.35,426.803c4.069,4.069,4.069,10.668,0,14.738l0,0
|
||||
C438.281,445.61,431.682,445.61,427.612,441.54z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
1
build.bat
Normal file
@@ -0,0 +1 @@
|
||||
pyinstaller --noconfirm --onedir --onefile --windowed --icon .\assets\Icone.ico --name "La Tanière Launcher" .\src\mainwindow.py --paths ".\.venv\Lib\site-packages\" --add-data ".\styles\styles.qss:styles" --add-data ".\ui\mainwindow.ui:ui" --hidden-import win11toast
|
||||
@@ -1,7 +0,0 @@
|
||||
patch_note = (
|
||||
"## 🚧 Modifications\n"
|
||||
" \n\n"
|
||||
" 🏫 De l'auto école: nouvelle emplacement et nouveau circuit\n\n"
|
||||
" 🚗 Du concessionnaire\n\n"
|
||||
" 📒 Module de saisie pour le SAPD\n\n"
|
||||
)
|
||||
48
frameless.py
@@ -1,48 +0,0 @@
|
||||
import sys
|
||||
import os
|
||||
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget
|
||||
from PyQt6.QtCore import Qt, QPoint
|
||||
|
||||
# À placer tout en haut, avant les imports PyQt6 si possible
|
||||
os.environ["QT_QPA_PLATFORM"] = "xcb"
|
||||
|
||||
class FenetreSansTitre(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
|
||||
self.resize(400, 300)
|
||||
|
||||
# IMPORTANT : On active le suivi de souris
|
||||
self.setMouseTracking(True)
|
||||
|
||||
layout = QVBoxLayout()
|
||||
btn_quitter = QPushButton("Quitter")
|
||||
btn_quitter.clicked.connect(self.close)
|
||||
layout.addWidget(btn_quitter)
|
||||
|
||||
container = QWidget()
|
||||
container.setLayout(layout)
|
||||
self.setCentralWidget(container)
|
||||
|
||||
self._drag_pos = None
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
if event.button() == Qt.MouseButton.LeftButton:
|
||||
# On enregistre la position du clic RELATIVE au coin haut-gauche de la fenêtre
|
||||
self._drag_pos = event.position().toPoint()
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
if self._drag_pos is not None:
|
||||
# On déplace la fenêtre vers la position globale du curseur
|
||||
# MOINS le décalage initial (offset) pour éviter que le curseur ne saute au centre
|
||||
self.move(event.globalPosition().toPoint() - self._drag_pos)
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
self._drag_pos = None
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
fenetre = FenetreSansTitre()
|
||||
fenetre.show()
|
||||
sys.exit(app.exec())
|
||||
@@ -1,53 +0,0 @@
|
||||
import sys
|
||||
import os
|
||||
from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton, QVBoxLayout, QWidget
|
||||
from PyQt6.QtCore import Qt, QPoint
|
||||
|
||||
# À placer tout en haut, avant les imports PyQt6 si possible
|
||||
os.environ["QT_QPA_PLATFORM"] = "xcb"
|
||||
|
||||
class FenetreSansTitre(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
# 1. Retirer la barre de titre
|
||||
self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
|
||||
self.resize(400, 300)
|
||||
|
||||
# Interface simple
|
||||
layout = QVBoxLayout()
|
||||
btn_quitter = QPushButton("Fermer la fenêtre")
|
||||
btn_quitter.clicked.connect(self.close)
|
||||
layout.addWidget(btn_quitter)
|
||||
|
||||
container = QWidget()
|
||||
container.setLayout(layout)
|
||||
self.setCentralWidget(container)
|
||||
|
||||
# Variable pour stocker la position du clic
|
||||
self.old_pos = None
|
||||
|
||||
# --- Logique de déplacement ---
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
if event.button() == Qt.MouseButton.LeftButton:
|
||||
# On sauvegarde la position relative du curseur dans la fenêtre
|
||||
self.old_pos = event.globalPosition().toPoint()
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
if self.old_pos is not None:
|
||||
# Calcul de la distance parcourue
|
||||
delta = QPoint(event.globalPosition().toPoint() - self.old_pos)
|
||||
# Déplacement de la fenêtre
|
||||
self.move(self.x() + delta.x(), self.y() + delta.y())
|
||||
# Mise à jour de la position de référence
|
||||
self.old_pos = event.globalPosition().toPoint()
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
self.old_pos = None
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
fenetre = FenetreSansTitre()
|
||||
fenetre.show()
|
||||
sys.exit(app.exec())
|
||||
117
mainwindow.py
@@ -1,117 +0,0 @@
|
||||
import sys
|
||||
import os
|
||||
from PyQt6 import QtGui, QtWidgets
|
||||
from PyQt6 import uic
|
||||
from PyQt6.QtCore import Qt
|
||||
from PyQt6.QtGui import QFontDatabase, QFont, QColor
|
||||
from PyQt6.QtWidgets import QApplication, QMainWindow
|
||||
|
||||
from win11toast import toast
|
||||
|
||||
from slidergroovecolorstyle import ThinSubPageLineStyle, ThinAddPageLineStyle
|
||||
|
||||
# Compile resources.qrc into resources_rc.py
|
||||
# rcc -g python resources.qrc -o resources_rc.py
|
||||
|
||||
import resources # This is generated from the .qrc file
|
||||
|
||||
# À placer tout en haut, avant les imports PyQt6 si possible
|
||||
if sys.platform.startswith('linux'):
|
||||
os.environ["QT_QPA_PLATFORM"] = "xcb"
|
||||
|
||||
# Remove this into final release
|
||||
from fake_patch_notes import patch_note
|
||||
NO_STAFF = True
|
||||
|
||||
def load_custom_font():
|
||||
# Load font from Qt resource
|
||||
font_id = QFontDatabase.addApplicationFont(":/assets/Avocado-Cake-Demo.otf")
|
||||
if font_id == -1:
|
||||
raise RuntimeError("Failed to load font from resources.")
|
||||
|
||||
# Get the family name of the loaded font
|
||||
font_families = QFontDatabase.applicationFontFamilies(font_id)
|
||||
if not font_families:
|
||||
raise RuntimeError("No font families found in the loaded font.")
|
||||
return font_families[0]
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# Remove the title bar and window frame
|
||||
self.setWindowFlags(Qt.WindowType.FramelessWindowHint |Qt.WindowType.Window)
|
||||
|
||||
# Optional: Make background transparent (if you want rounded corners, etc.)
|
||||
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
|
||||
|
||||
# Track mouse position for dragging
|
||||
self._drag_pos = None
|
||||
|
||||
# Load font family from resource
|
||||
font_family = load_custom_font()
|
||||
|
||||
uic.loadUi("mainwindow.ui", self)
|
||||
|
||||
# Adjust UI
|
||||
self.maintitle_label.setFont(QFont(font_family, 38))
|
||||
self.subtitle_label.setStyleSheet("color: rgb(163, 177, 198)")
|
||||
#self.horizontalSlider.setStyle(ThinAddPageLineStyle(app.style(), QColor("#2196F3")))
|
||||
|
||||
if NO_STAFF :
|
||||
self.staff_btn.hide()
|
||||
self.spacer_substitution.hide()
|
||||
|
||||
self.info_text.setMarkdown(patch_note)
|
||||
|
||||
# Find the button by its objectName in Qt Designer
|
||||
# Example: objectName = "close_btn"
|
||||
self.close_btn.clicked.connect(self.close_link)
|
||||
self.minimize_btn.clicked.connect(self.minimize_link)
|
||||
|
||||
self.connexion_btn.clicked.connect(self.connexion_btn_link)
|
||||
|
||||
def close_link(self):
|
||||
sys.exit(app.exec())
|
||||
|
||||
def minimize_link(self):
|
||||
# Minimize the application
|
||||
self.setWindowState(Qt.WindowState.WindowMinimized)
|
||||
|
||||
# Mouse press event to start dragging
|
||||
def mousePressEvent(self, event):
|
||||
if event.button() == Qt.MouseButton.LeftButton:
|
||||
self._drag_pos = event.globalPosition().toPoint() - self.frameGeometry().topLeft()
|
||||
event.accept()
|
||||
|
||||
# Mouse move event to drag window
|
||||
def mouseMoveEvent(self, event):
|
||||
if event.buttons() == Qt.MouseButton.LeftButton and self._drag_pos is not None:
|
||||
self.move(event.globalPosition().toPoint() - self._drag_pos)
|
||||
event.accept()
|
||||
|
||||
# Mouse release event to stop dragging
|
||||
def mouseReleaseEvent(self, event):
|
||||
self._drag_pos = None
|
||||
event.accept()
|
||||
|
||||
def connexion_btn_link(self):
|
||||
toast('Hello Python🐍')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
with open('styles.qss', 'r') as f:
|
||||
style = f.read()
|
||||
|
||||
# Set the stylesheet of the application
|
||||
app.setStyleSheet(style)
|
||||
|
||||
# Load and set the global font
|
||||
custom_font = QFont(load_custom_font(), 16)
|
||||
if custom_font:
|
||||
app.setFont(custom_font)
|
||||
window = MainWindow()
|
||||
window.show()
|
||||
sys.exit(app.exec())
|
||||
@@ -1,9 +0,0 @@
|
||||
[project]
|
||||
name = "LaTaniere_UI"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.14"
|
||||
dependencies = [
|
||||
"pyside6>=6.10.2",
|
||||
]
|
||||
51
readme.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# LaTaniere Launcher UI
|
||||
|
||||
⚠️ you need [Qt Designer](https://build-system.fman.io/qt-designer-download).
|
||||
|
||||
## First: create virtualenv
|
||||
|
||||
python -m venv .venv
|
||||
|
||||
## Second: activate your virtual environment
|
||||
|
||||
### Windows
|
||||
|
||||
Execute in powershell:
|
||||
|
||||
```powershell
|
||||
.venv/bin/activate.ps1
|
||||
```
|
||||
|
||||
or batch file
|
||||
|
||||
```bat
|
||||
.venv/bin/activate.bat
|
||||
```
|
||||
|
||||
### Linux
|
||||
|
||||
Execute into terminal in project folder:
|
||||
`source .venv/bin/actiave`
|
||||
|
||||
----
|
||||
|
||||
## Third install packages
|
||||
|
||||
Ensure your virtual environment is active and execute these commands within it.
|
||||
|
||||
### Using Pip
|
||||
|
||||
#### Global packages
|
||||
|
||||
`pip install -r .\requirements.txt`
|
||||
|
||||
#### packages for Windows only
|
||||
|
||||
`pip install -r .\windows_requirements.txt`
|
||||
|
||||
### Using install.py script
|
||||
|
||||
Execute `python install.py`
|
||||
Note: in case if you aren't virtual environment, the script stop.
|
||||
|
||||
Enjoy.
|
||||
@@ -1,31 +1,21 @@
|
||||
certifi==2026.2.25
|
||||
distlib==0.4.0
|
||||
filelock==3.25.0
|
||||
altgraph==0.17.5
|
||||
packaging==26.0
|
||||
pipenv==2026.0.3
|
||||
platformdirs==4.9.2
|
||||
PyQt6==6.10.2
|
||||
PyQt6-Qt6==6.10.2
|
||||
PyQt6_sip==13.11.0
|
||||
PySide6==6.10.2
|
||||
pefile==2024.8.26
|
||||
pyinstaller==6.19.0
|
||||
pyinstaller-hooks-contrib==2026.3
|
||||
PySide6_Addons==6.10.2
|
||||
PySide6_Essentials==6.10.2
|
||||
python-discovery==1.1.0
|
||||
setuptools==82.0.0
|
||||
pywin32-ctypes==0.2.3
|
||||
setuptools==82.0.1
|
||||
shiboken6==6.10.2
|
||||
typing_extensions==4.15.0
|
||||
virtualenv==21.1.0
|
||||
win11toast==0.36.3
|
||||
winrt-runtime==3.2.1
|
||||
winrt-Windows.Data.Xml.Dom==3.2.1
|
||||
winrt-Windows.Foundation==3.2.1
|
||||
winrt-Windows.Foundation.Collections==3.2.1
|
||||
winrt-Windows.Globalization==3.2.1
|
||||
winrt-Windows.Graphics.Imaging==3.2.1
|
||||
winrt-Windows.Media.Core==3.2.1
|
||||
winrt-Windows.Media.Ocr==3.2.1
|
||||
winrt-Windows.Media.Playback==3.2.1
|
||||
winrt-Windows.Media.SpeechSynthesis==3.2.1
|
||||
winrt-Windows.Storage==3.2.1
|
||||
winrt-Windows.Storage.Streams==3.2.1
|
||||
winrt-Windows.UI.Notifications==3.2.1
|
||||
certifi==2026.1.4
|
||||
cffi==2.0.0
|
||||
charset-normalizer==3.4.4
|
||||
cryptography==46.0.4
|
||||
idna==3.11
|
||||
psutil==7.2.2
|
||||
puremagic==1.30
|
||||
pycparser==3.0
|
||||
pypresence==4.6.1
|
||||
requests==2.32.5
|
||||
urllib3==2.6.3
|
||||
|
||||
17792
resources.py
@@ -1,8 +1,17 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>assets/closed-store-info.svg</file>
|
||||
<file>assets/letter-i-info.svg</file>
|
||||
<file>assets/open-store-info.svg</file>
|
||||
<file>assets/tools-repair.svg</file>
|
||||
<file>assets/Icon.ico</file>
|
||||
<file>assets/sound-speaker.svg</file>
|
||||
<file>assets/the-beat-of-nature.mp3</file>
|
||||
<file>assets/computer-tv.svg</file>
|
||||
<file>assets/padlock-lock.svg</file>
|
||||
<file>assets/logo.png</file>
|
||||
<file>assets/system-shutdown.png</file>
|
||||
<file>assets/discord-icon.svg</file>
|
||||
<file>assets/Avocado-Cake-Demo.otf</file>
|
||||
<file>assets/background.png</file>
|
||||
<file>assets/Icone.ico</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -1,272 +0,0 @@
|
||||
from PyQt6.QtCore import Qt
|
||||
from PyQt6.QtWidgets import (
|
||||
QSlider, QProxyStyle, QStyle
|
||||
)
|
||||
from PyQt6.QtGui import QColor
|
||||
|
||||
class SliderGrooveColorStyle(QProxyStyle):
|
||||
def __init__(self, base_style=None, groove_color=QColor("lightblue")):
|
||||
super().__init__(base_style)
|
||||
self.groove_color = groove_color
|
||||
|
||||
def drawComplexControl(self, control, option, painter, widget=None):
|
||||
if control == QStyle.ComplexControl.CC_Slider and isinstance(widget, QSlider):
|
||||
|
||||
# Récupérer la zone du groove
|
||||
groove_rect = self.subControlRect(
|
||||
QStyle.ComplexControl.CC_Slider,
|
||||
option,
|
||||
QStyle.SubControl.SC_SliderGroove,
|
||||
widget
|
||||
)
|
||||
|
||||
# Dessiner notre fond
|
||||
painter.save()
|
||||
painter.setBrush(self.groove_color)
|
||||
painter.setPen(Qt.PenStyle.NoPen)
|
||||
painter.drawRect(groove_rect)
|
||||
painter.restore()
|
||||
|
||||
# Puis laisser Qt dessiner normalement (handle etc.)
|
||||
super().drawComplexControl(control, option, painter, widget)
|
||||
return
|
||||
|
||||
super().drawComplexControl(control, option, painter, widget)
|
||||
|
||||
class SliderSubPageColorStyle(QProxyStyle):
|
||||
def __init__(self, base_style=None, color=QColor("#4CAF50")):
|
||||
super().__init__(base_style)
|
||||
self.color = color
|
||||
|
||||
def drawComplexControl(self, control, option, painter, widget=None):
|
||||
if control == QStyle.ComplexControl.CC_Slider and isinstance(widget, QSlider):
|
||||
|
||||
# Laisser Qt dessiner le slider normalement
|
||||
super().drawComplexControl(control, option, painter, widget)
|
||||
|
||||
# Récupérer les rectangles du groove et du handle
|
||||
groove_rect = self.subControlRect(
|
||||
control,
|
||||
option,
|
||||
QStyle.SubControl.SC_SliderGroove,
|
||||
widget
|
||||
)
|
||||
|
||||
handle_rect = self.subControlRect(
|
||||
control,
|
||||
option,
|
||||
QStyle.SubControl.SC_SliderHandle,
|
||||
widget
|
||||
)
|
||||
|
||||
painter.save()
|
||||
painter.setBrush(self.color)
|
||||
painter.setPen(Qt.PenStyle.NoPen)
|
||||
|
||||
if widget.orientation() == Qt.Orientation.Horizontal:
|
||||
# Partie avant le handle (gauche → centre du handle)
|
||||
sub_rect = groove_rect.adjusted(
|
||||
0,
|
||||
0,
|
||||
handle_rect.center().x() - groove_rect.right(),
|
||||
0
|
||||
)
|
||||
else:
|
||||
# Vertical (bas → centre du handle)
|
||||
sub_rect = groove_rect.adjusted(
|
||||
0,
|
||||
handle_rect.center().y() - groove_rect.bottom(),
|
||||
0,
|
||||
0
|
||||
)
|
||||
|
||||
painter.drawRect(sub_rect)
|
||||
painter.restore()
|
||||
|
||||
return
|
||||
|
||||
super().drawComplexControl(control, option, painter, widget)
|
||||
|
||||
class SliderAddPageColorStyle(QProxyStyle):
|
||||
def __init__(self, base_style=None, color=QColor("#FF9800")):
|
||||
super().__init__(base_style)
|
||||
self.color = color
|
||||
|
||||
def drawComplexControl(self, control, option, painter, widget=None):
|
||||
if control == QStyle.ComplexControl.CC_Slider and isinstance(widget, QSlider):
|
||||
|
||||
# Récupérer groove + handle
|
||||
groove_rect = self.subControlRect(
|
||||
control,
|
||||
option,
|
||||
QStyle.SubControl.SC_SliderGroove,
|
||||
widget
|
||||
)
|
||||
|
||||
handle_rect = self.subControlRect(
|
||||
control,
|
||||
option,
|
||||
QStyle.SubControl.SC_SliderHandle,
|
||||
widget
|
||||
)
|
||||
|
||||
painter.save()
|
||||
painter.setBrush(self.color)
|
||||
painter.setPen(Qt.PenStyle.NoPen)
|
||||
|
||||
if widget.orientation() == Qt.Orientation.Horizontal:
|
||||
# Partie après le handle (centre → fin)
|
||||
add_rect = groove_rect.adjusted(
|
||||
handle_rect.center().x() - groove_rect.left(),
|
||||
0,
|
||||
0,
|
||||
0
|
||||
)
|
||||
else:
|
||||
# Vertical (centre → haut)
|
||||
add_rect = groove_rect.adjusted(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
handle_rect.center().y() - groove_rect.top()
|
||||
)
|
||||
|
||||
painter.drawRect(add_rect)
|
||||
painter.restore()
|
||||
|
||||
# IMPORTANT : Qt dessine ensuite le handle par-dessus
|
||||
super().drawComplexControl(control, option, painter, widget)
|
||||
return
|
||||
|
||||
super().drawComplexControl(control, option, painter, widget)
|
||||
|
||||
class ThinAddPageLineStyle(QProxyStyle):
|
||||
def __init__(self, base_style=None, color=QColor("#E91E63")):
|
||||
super().__init__(base_style)
|
||||
self.color = color
|
||||
|
||||
def drawComplexControl(self, control, option, painter, widget=None):
|
||||
if control == QStyle.ComplexControl.CC_Slider and isinstance(widget, QSlider):
|
||||
|
||||
groove_rect = self.subControlRect(
|
||||
control,
|
||||
option,
|
||||
QStyle.SubControl.SC_SliderGroove,
|
||||
widget
|
||||
)
|
||||
|
||||
handle_rect = self.subControlRect(
|
||||
control,
|
||||
option,
|
||||
QStyle.SubControl.SC_SliderHandle,
|
||||
widget
|
||||
)
|
||||
|
||||
painter.save()
|
||||
painter.setBrush(self.color)
|
||||
painter.setPen(Qt.PenStyle.NoPen)
|
||||
|
||||
if widget.orientation() == Qt.Orientation.Horizontal:
|
||||
# Épaisseur fine (2 px)
|
||||
thickness = 2
|
||||
|
||||
y = groove_rect.center().y() - thickness // 2
|
||||
|
||||
add_rect = groove_rect.adjusted(
|
||||
handle_rect.center().x() - groove_rect.left(),
|
||||
0,
|
||||
0,
|
||||
0
|
||||
)
|
||||
|
||||
add_rect.setTop(y)
|
||||
add_rect.setHeight(thickness)
|
||||
|
||||
else:
|
||||
thickness = 2
|
||||
|
||||
x = groove_rect.center().x() - thickness // 2
|
||||
|
||||
add_rect = groove_rect.adjusted(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
handle_rect.center().y() - groove_rect.top()
|
||||
)
|
||||
|
||||
add_rect.setLeft(x)
|
||||
add_rect.setWidth(thickness)
|
||||
|
||||
painter.drawRect(add_rect)
|
||||
painter.restore()
|
||||
|
||||
# Dessiner ensuite le slider normalement (handle au-dessus)
|
||||
super().drawComplexControl(control, option, painter, widget)
|
||||
return
|
||||
|
||||
super().drawComplexControl(control, option, painter, widget)
|
||||
|
||||
class ThinSubPageLineStyle(QProxyStyle):
|
||||
def __init__(self, base_style=None, color=QColor("#4CAF50")):
|
||||
super().__init__(base_style)
|
||||
self.color = color
|
||||
|
||||
def drawComplexControl(self, control, option, painter, widget=None):
|
||||
if control == QStyle.ComplexControl.CC_Slider and isinstance(widget, QSlider):
|
||||
|
||||
groove_rect = self.subControlRect(
|
||||
control,
|
||||
option,
|
||||
QStyle.SubControl.SC_SliderGroove,
|
||||
widget
|
||||
)
|
||||
|
||||
handle_rect = self.subControlRect(
|
||||
control,
|
||||
option,
|
||||
QStyle.SubControl.SC_SliderHandle,
|
||||
widget
|
||||
)
|
||||
|
||||
painter.save()
|
||||
painter.setBrush(self.color)
|
||||
painter.setPen(Qt.PenStyle.NoPen)
|
||||
|
||||
# Épaisseur fine (ajuste si besoin)
|
||||
thickness = 2
|
||||
|
||||
if widget.orientation() == Qt.Orientation.Horizontal:
|
||||
|
||||
y = groove_rect.center().y() - thickness // 2
|
||||
|
||||
sub_rect = groove_rect.adjusted(
|
||||
0,
|
||||
0,
|
||||
handle_rect.center().x() - groove_rect.right(),
|
||||
0
|
||||
)
|
||||
|
||||
sub_rect.setTop(y)
|
||||
sub_rect.setHeight(thickness)
|
||||
|
||||
else:
|
||||
x = groove_rect.center().x() - thickness // 2
|
||||
|
||||
sub_rect = groove_rect.adjusted(
|
||||
0,
|
||||
handle_rect.center().y() - groove_rect.bottom(),
|
||||
0,
|
||||
0
|
||||
)
|
||||
|
||||
sub_rect.setLeft(x)
|
||||
sub_rect.setWidth(thickness)
|
||||
|
||||
painter.drawRect(sub_rect)
|
||||
painter.restore()
|
||||
|
||||
# Qt redessine le slider (handle au-dessus)
|
||||
super().drawComplexControl(control, option, painter, widget)
|
||||
return
|
||||
|
||||
super().drawComplexControl(control, option, painter, widget)
|
||||
137
src/config/config_manager.py
Normal file
@@ -0,0 +1,137 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, NotRequired, TypedDict, cast
|
||||
|
||||
from tools.utils import get_executable_dir
|
||||
|
||||
class ConfigData(TypedDict):
|
||||
discord_user_id: NotRequired[str]
|
||||
volume: NotRequired[int]
|
||||
|
||||
Validator = Callable[[Any], bool]
|
||||
Normalizer = Callable[[Any], Any]
|
||||
|
||||
class ConfigField(TypedDict):
|
||||
default: Any
|
||||
validator: Validator
|
||||
normalizer: Normalizer
|
||||
|
||||
CONFIG_PATH = get_executable_dir() / "config.json"
|
||||
|
||||
DISCORD_USER_KEY = "discord_user_id"
|
||||
VOLUME_KEY = "volume"
|
||||
|
||||
CONFIG_SCHEMA: dict[str, ConfigField] = {
|
||||
DISCORD_USER_KEY: {
|
||||
"default": "",
|
||||
"validator": lambda value: isinstance(value, str),
|
||||
"normalizer": lambda value: str(value).strip(),
|
||||
},
|
||||
VOLUME_KEY: {
|
||||
"default": 30,
|
||||
"validator": lambda value: isinstance(value, int) and 0 <= value <= 100,
|
||||
"normalizer": lambda value: max(0, min(int(value), 100)),
|
||||
},
|
||||
}
|
||||
|
||||
class ConfigManager:
|
||||
def __init__(self, path: Path | None = None) -> None:
|
||||
self.path = path or CONFIG_PATH
|
||||
self._data: ConfigData = self._load()
|
||||
self._dirty = False
|
||||
|
||||
# Lecture du fichier de configuration
|
||||
def _load(self) -> ConfigData:
|
||||
if not self.path.exists():
|
||||
return {}
|
||||
|
||||
try:
|
||||
with self.path.open("r", encoding="utf-8") as file:
|
||||
data = json.load(file)
|
||||
except (json.JSONDecodeError, OSError):
|
||||
return {}
|
||||
|
||||
if not isinstance(data, dict):
|
||||
return {}
|
||||
|
||||
return cast(ConfigData, data)
|
||||
|
||||
# Sauvegarde du fichier de configuration
|
||||
def save(self) -> None:
|
||||
if not self._dirty:
|
||||
return
|
||||
|
||||
self.path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with self.path.open("w", encoding="utf-8") as file:
|
||||
json.dump(self._data, file, indent=4, ensure_ascii=False)
|
||||
|
||||
self._dirty = False
|
||||
|
||||
def _get_field(self, key: str) -> ConfigField:
|
||||
if key not in CONFIG_SCHEMA:
|
||||
raise KeyError(f"Unknown config key: {key}")
|
||||
return CONFIG_SCHEMA[key]
|
||||
|
||||
def get(self, key: str) -> Any:
|
||||
field = self._get_field(key)
|
||||
value = self._data.get(key, field["default"])
|
||||
|
||||
if not field["validator"](value):
|
||||
return field["default"]
|
||||
|
||||
return value
|
||||
|
||||
def set(self, key: str, value: Any) -> None:
|
||||
field = self._get_field(key)
|
||||
|
||||
normalized = field["normalizer"](value)
|
||||
|
||||
if not field["validator"](normalized):
|
||||
raise ValueError(f"Invalid value for {key}")
|
||||
|
||||
if self._data.get(key) == normalized:
|
||||
return
|
||||
|
||||
self._data[key] = normalized
|
||||
self._dirty = True
|
||||
|
||||
def reset_all(self) -> None:
|
||||
defaults: ConfigData = cast(
|
||||
ConfigData,
|
||||
{key: field["default"] for key, field in CONFIG_SCHEMA.items()},
|
||||
)
|
||||
self.save(defaults)
|
||||
|
||||
def get_all(self) -> ConfigData:
|
||||
return cast(
|
||||
ConfigData,
|
||||
{key: self.get(key) for key in CONFIG_SCHEMA},
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# SETTERS MÉTIER
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Set Discord ID
|
||||
def set_discord_user(self, user_id: str) -> None:
|
||||
self.set(DISCORD_USER_KEY, user_id)
|
||||
|
||||
# Set volume
|
||||
def set_volume(self, volume: int) -> None:
|
||||
self.set(VOLUME_KEY, volume)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# GETTERS MÉTIER
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Get discord ID
|
||||
def get_default(self, key: str):
|
||||
return CONFIG_SCHEMA[key]["default"]
|
||||
|
||||
# Get volume value
|
||||
def get_discord_user(self) -> str:
|
||||
return cast(str, self.get(DISCORD_USER_KEY))
|
||||
|
||||
def get_volume(self) -> int:
|
||||
return cast(int, self.get(VOLUME_KEY))
|
||||
43
src/config/constants.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from enum import Enum
|
||||
|
||||
from PySide6.QtGui import QColor
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Constants
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
NO_STAFF = True
|
||||
NO_WHITELIST = False
|
||||
|
||||
REDIRECT_URI = "http://localhost:5000/callback"
|
||||
SCOPES = ["identify"]
|
||||
CLIENT_ID = "1240007913175781508"
|
||||
AUTENTICATION_SUCCESS_MESSAGE = """
|
||||
<html>
|
||||
<head>
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||
<meta content="utf-8" http-equiv="encoding">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Authentication réussie</h1>
|
||||
<p>Vous pouvez maintenant fermer cette fenêtre et revenir au launcher de La Tanière.</p>
|
||||
</body>
|
||||
</html>
|
||||
""".encode('utf-8')
|
||||
# ---------------------------------------------------------------------------
|
||||
# ENUMS
|
||||
# ---------------------------------------------------------------------------
|
||||
class Resources(Enum):
|
||||
MP3 = ":/assets/the-beat-of-nature.mp3"
|
||||
FONT = ":/assets/Avocado-Cake-Demo.otf"
|
||||
|
||||
class Urls(Enum):
|
||||
DISCORD = "https://discord.gg/A7eanmSkp2"
|
||||
INTRANET = "https://la-taniere.fun/connexion/"
|
||||
API_URL = 'https://prod.la-taniere.fun:30121/'
|
||||
|
||||
class Glow(Enum):
|
||||
COLOR = QColor(255, 140, 0, 255)
|
||||
BLUR_BASE = 15
|
||||
BLUR_PEAK = 70
|
||||
ANIM_DURATION = 1200
|
||||
86
src/controllers/audio_controller.py
Normal file
@@ -0,0 +1,86 @@
|
||||
from PySide6.QtCore import QFile, QBuffer, QByteArray, QIODevice
|
||||
from PySide6.QtMultimedia import QMediaPlayer, QAudioOutput
|
||||
|
||||
from config.config_manager import ConfigManager, VOLUME_KEY
|
||||
|
||||
from config.constants import Resources
|
||||
|
||||
class AudioController:
|
||||
# Encapsule toute la logique audio : lecture, volume, mute.
|
||||
|
||||
def __init__(self, config: ConfigManager, slider, mute_btn):
|
||||
self._config = config
|
||||
self._slider = slider
|
||||
self._mute_btn = mute_btn
|
||||
|
||||
# Lecteur
|
||||
self._player = QMediaPlayer()
|
||||
self._output = QAudioOutput()
|
||||
self._player.setAudioOutput(self._output)
|
||||
self._player.setLoops(-1)
|
||||
|
||||
# Chargement du MP3 depuis les ressources Qt
|
||||
mp3file = QFile(Resources.MP3.value)
|
||||
mp3file.open(QFile.ReadOnly)
|
||||
mp3data = mp3file.readAll()
|
||||
mp3file.close()
|
||||
|
||||
# Mise en buffer du MP3
|
||||
self._buffer = QBuffer()
|
||||
self._buffer.setData(QByteArray(mp3data))
|
||||
self._buffer.open(QIODevice.ReadOnly)
|
||||
self._player.setSourceDevice(self._buffer)
|
||||
|
||||
# État initial du lecteur
|
||||
volume = config.get_volume()
|
||||
self._is_muted = volume == 0
|
||||
self._previous_volume = volume if volume != 0 else config.get_default(VOLUME_KEY)
|
||||
|
||||
self._apply_volume(volume, save=False)
|
||||
self._refresh_mute_btn()
|
||||
self._player.play()
|
||||
|
||||
# Connexions
|
||||
self._slider.valueChanged.connect(self._on_slider_changed)
|
||||
self._mute_btn.clicked.connect(self.toggle_mute)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Public API
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def toggle_mute(self) -> None:
|
||||
if not self._is_muted:
|
||||
self._previous_volume = self._slider.value()
|
||||
self._apply_volume(0)
|
||||
self._is_muted = True
|
||||
else:
|
||||
self._apply_volume(self._previous_volume)
|
||||
self._is_muted = False
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Private helpers
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _on_slider_changed(self, value: int) -> None:
|
||||
self._is_muted = value == 0
|
||||
self._output.setVolume(value / 100.0)
|
||||
self._config.set_volume(value)
|
||||
self._refresh_mute_btn()
|
||||
|
||||
def _apply_volume(self, value: int, save: bool = True) -> None:
|
||||
self._slider.blockSignals(True)
|
||||
self._slider.setValue(value)
|
||||
self._slider.blockSignals(False)
|
||||
|
||||
self._output.setVolume(value / 100.0)
|
||||
|
||||
if save:
|
||||
self._config.set_volume(value)
|
||||
|
||||
self._refresh_mute_btn()
|
||||
|
||||
def _refresh_mute_btn(self) -> None:
|
||||
muted = self._slider.value() == 0
|
||||
self._mute_btn.setProperty("muted", muted)
|
||||
self._mute_btn.style().unpolish(self._mute_btn)
|
||||
self._mute_btn.style().polish(self._mute_btn)
|
||||
32
src/controllers/glow_animator.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from PySide6.QtCore import QPropertyAnimation, QEasingCurve
|
||||
from PySide6.QtWidgets import QGraphicsDropShadowEffect
|
||||
|
||||
from config.constants import Glow
|
||||
|
||||
|
||||
class GlowAnimator:
|
||||
# Gère l'effet de lueur pulsée sur un widget.
|
||||
|
||||
def __init__(self, widget):
|
||||
self._widget = widget
|
||||
|
||||
self._effect = QGraphicsDropShadowEffect(widget)
|
||||
self._effect.setBlurRadius(Glow.BLUR_BASE.value)
|
||||
self._effect.setOffset(0, 0)
|
||||
self._effect.setColor(Glow.COLOR.value)
|
||||
|
||||
self._anim = QPropertyAnimation(self._effect, b"blurRadius")
|
||||
self._anim.setDuration(Glow.ANIM_DURATION.value)
|
||||
self._anim.setStartValue(Glow.BLUR_BASE.value)
|
||||
self._anim.setKeyValueAt(0.5, Glow.BLUR_PEAK.value)
|
||||
self._anim.setEndValue(Glow.BLUR_BASE.value)
|
||||
self._anim.setEasingCurve(QEasingCurve.InOutQuad)
|
||||
self._anim.setLoopCount(-1)
|
||||
|
||||
def start(self) -> None:
|
||||
self._widget.setGraphicsEffect(self._effect)
|
||||
self._anim.start()
|
||||
|
||||
def stop(self) -> None:
|
||||
self._anim.stop()
|
||||
self._widget.setGraphicsEffect(None)
|
||||
25
src/controllers/window_dragger.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from PySide6 import QtGui
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtWidgets import QMainWindow
|
||||
|
||||
|
||||
class WindowDragger:
|
||||
# Permet de déplacer une fenêtre sans barre de titre.
|
||||
|
||||
def __init__(self, window: QMainWindow):
|
||||
self._window = window
|
||||
self._drag_pos = None
|
||||
|
||||
def mouse_press(self, event: QtGui.QMouseEvent) -> None:
|
||||
if event.button() == Qt.MouseButton.LeftButton:
|
||||
self._drag_pos = (
|
||||
event.globalPosition().toPoint()
|
||||
- self._window.frameGeometry().topLeft()
|
||||
)
|
||||
|
||||
def mouse_move(self, event: QtGui.QMouseEvent) -> None:
|
||||
if event.buttons() & Qt.MouseButton.LeftButton and self._drag_pos is not None:
|
||||
self._window.move(event.globalPosition().toPoint() - self._drag_pos)
|
||||
|
||||
def mouse_release(self, _event) -> None:
|
||||
self._drag_pos = None
|
||||
84
src/discord/discord_oauth.py
Normal file
@@ -0,0 +1,84 @@
|
||||
import requests
|
||||
import webbrowser
|
||||
import os
|
||||
from urllib.parse import urlencode
|
||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||
from fivemserver.get_server_token import GetServerTokenForDiscord
|
||||
from config.constants import CLIENT_ID, REDIRECT_URI, SCOPES, AUTENTICATION_SUCCESS_MESSAGE
|
||||
|
||||
# Disable stderr output
|
||||
os.environ['PYTHONWARNINGS'] = 'ignore'
|
||||
|
||||
class OAuthCallbackHandler(BaseHTTPRequestHandler):
|
||||
code: str | None = None
|
||||
|
||||
# Ajoute ceci pour empêcher le serveur d'écrire dans la console/stderr
|
||||
def log_message(self, format, *args):
|
||||
return # Ne fait rien, donc pas de blocage sur stdout/stderr
|
||||
|
||||
def do_GET(self):
|
||||
"""
|
||||
callback pour discord auth
|
||||
"""
|
||||
if "/callback" in self.path:
|
||||
query = self.path.split("?")[1]
|
||||
params = dict(p.split("=") for p in query.split("&"))
|
||||
OAuthCallbackHandler.code = params.get("code")
|
||||
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", "text/html")
|
||||
self.end_headers()
|
||||
self.wfile.write(AUTENTICATION_SUCCESS_MESSAGE)
|
||||
|
||||
# return discord application id (client id)
|
||||
def get_discord_client_id() -> str:
|
||||
"""
|
||||
return discord application id
|
||||
"""
|
||||
return CLIENT_ID
|
||||
|
||||
# return discord user id
|
||||
def get_discord_user_id() -> str:
|
||||
"""
|
||||
Retourne l'id du compte discord de l'utilisateur via l'oauh discord.
|
||||
"""
|
||||
|
||||
# récupération des infos serveur la tanière
|
||||
# récupération d
|
||||
session_id = GetServerTokenForDiscord.authenticate()
|
||||
client_secret = GetServerTokenForDiscord.get_token(session_id)
|
||||
|
||||
auth_url = "https://discord.com/api/oauth2/authorize"
|
||||
params = {
|
||||
"client_id": CLIENT_ID,
|
||||
"redirect_uri": REDIRECT_URI,
|
||||
"response_type": "code",
|
||||
"scope": " ".join(SCOPES),
|
||||
}
|
||||
|
||||
webbrowser.open(f"{auth_url}?{urlencode(params)}")
|
||||
|
||||
server = HTTPServer(("localhost", 5000), OAuthCallbackHandler)
|
||||
server.handle_request()
|
||||
|
||||
if not OAuthCallbackHandler.code:
|
||||
raise RuntimeError("OAuth échoué")
|
||||
|
||||
token = requests.post(
|
||||
"https://discord.com/api/oauth2/token",
|
||||
data={
|
||||
"client_id": CLIENT_ID,
|
||||
"client_secret": client_secret,
|
||||
"grant_type": "authorization_code",
|
||||
"code": OAuthCallbackHandler.code,
|
||||
"redirect_uri": REDIRECT_URI,
|
||||
},
|
||||
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
||||
).json()
|
||||
|
||||
user = requests.get(
|
||||
"https://discord.com/api/users/@me",
|
||||
headers={"Authorization": f"Bearer {token['access_token']}"},
|
||||
).json()
|
||||
|
||||
return user["id"]
|
||||
53
src/discord/discord_tools.py
Normal file
@@ -0,0 +1,53 @@
|
||||
import psutil
|
||||
|
||||
from pypresence import Presence
|
||||
from fivemserver.get_server_token import GetServerTokenForDiscord
|
||||
from config.constants import Urls
|
||||
from discord.discord_oauth import CLIENT_ID
|
||||
|
||||
|
||||
class DiscordToken:
|
||||
"""
|
||||
Décode le token discord
|
||||
"""
|
||||
@staticmethod
|
||||
def decode_discord_token():
|
||||
discord_token = GetServerTokenForDiscord.get_token(
|
||||
GetServerTokenForDiscord.authenticate(Urls.API_URL.value)
|
||||
)
|
||||
return discord_token
|
||||
|
||||
|
||||
class CheckDiscord:
|
||||
@staticmethod
|
||||
def isdiscordrunning() -> bool:
|
||||
"""
|
||||
Vérifie si Discord est en cours d'exécution sur l'ordinateur. (Vérifie aussi pour Linux)
|
||||
"""
|
||||
for process in psutil.process_iter(["name"]):
|
||||
if (
|
||||
process.info["name"].lower() == "discord.exe"
|
||||
or process.info["name"].lower() == "discordcanary.exe"
|
||||
or process.info["name"].lower() == "discord"
|
||||
or process.info["name"].lower() == "discord canary"
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def isuserconnected() -> bool:
|
||||
"""
|
||||
Vérifie si l'utilisateur Discord est connecté.
|
||||
⚠️ne vérifie pas le user id discord.
|
||||
"""
|
||||
rpc = Presence(CLIENT_ID)
|
||||
try:
|
||||
rpc.connect()
|
||||
return True
|
||||
except Exception as e:
|
||||
return False
|
||||
finally:
|
||||
try:
|
||||
rpc.close()
|
||||
except Exception as e:
|
||||
pass
|
||||
13
src/fake_patch_notes.py
Normal file
@@ -0,0 +1,13 @@
|
||||
patch_note = (
|
||||
"## 🚧 Modifications\n"
|
||||
" \n\n"
|
||||
" 🏫 De l'auto école: nouvelle emplacement et nouveau circuit\n\n"
|
||||
" 🚗 Du concessionnaire\n\n"
|
||||
" 📒 Module de saisie pour le SAPD\n\n"
|
||||
"\n\n"
|
||||
"## 🚧 Modifications\n"
|
||||
" \n\n"
|
||||
" 🏫 De l'auto école: nouvelle emplacement et nouveau circuit\n\n"
|
||||
" 🚗 Du concessionnaire\n\n"
|
||||
" 📒 Module de saisie pour le SAPD\n\n"
|
||||
)
|
||||
76
src/fivemserver/get_server_token.py
Normal file
@@ -0,0 +1,76 @@
|
||||
import base64
|
||||
import requests
|
||||
from cryptography.hazmat.primitives import serialization, hashes
|
||||
from cryptography.hazmat.primitives.asymmetric import ec
|
||||
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
|
||||
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
||||
|
||||
from config.constants import Urls
|
||||
|
||||
class GetServerTokenForDiscord:
|
||||
derived_key: bytes | None = None
|
||||
|
||||
@staticmethod
|
||||
def authenticate(server = Urls.API_URL.value):
|
||||
|
||||
if server is None:
|
||||
server = Urls.API_URL.value
|
||||
# ==========================
|
||||
# Génération clé ECDH client
|
||||
# ==========================
|
||||
client_private = ec.generate_private_key(ec.SECP256R1())
|
||||
client_public = client_private.public_key()
|
||||
|
||||
client_pub_pem = client_public.public_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PublicFormat.SubjectPublicKeyInfo
|
||||
)
|
||||
|
||||
# ==========================
|
||||
# AUTH
|
||||
# ==========================
|
||||
auth = requests.post(server + "/api_v2/auth", verify=False, json={
|
||||
"client_pub": base64.b64encode(client_pub_pem).decode()
|
||||
}).json()
|
||||
|
||||
server_pub = serialization.load_pem_public_key(
|
||||
base64.b64decode(auth["server_pub"])
|
||||
)
|
||||
|
||||
shared_key = client_private.exchange(ec.ECDH(), server_pub)
|
||||
|
||||
GetServerTokenForDiscord.derived_key = HKDF(
|
||||
algorithm=hashes.SHA256(),
|
||||
length=32,
|
||||
salt=None,
|
||||
info=b"fivem-private-server"
|
||||
).derive(shared_key)
|
||||
|
||||
return auth["session_id"]
|
||||
|
||||
@staticmethod
|
||||
def get_token(session_id: bytes, server = Urls.API_URL.value):
|
||||
# ==========================
|
||||
# DISCORD TOKEN
|
||||
# ==========================
|
||||
if server is None:
|
||||
server = Urls.API_URL.value
|
||||
download = requests.post(server + "/api_v2/tkn_auth", verify=False, headers={
|
||||
"x-session-id": session_id
|
||||
}).json()
|
||||
|
||||
nonce = base64.b64decode(download["nonce"])
|
||||
encrypted_data = base64.b64decode(download["data"])
|
||||
|
||||
aesgcm = AESGCM(GetServerTokenForDiscord.derived_key) # type: ignore[arg-type]
|
||||
return aesgcm.decrypt(nonce, encrypted_data, None)
|
||||
|
||||
@staticmethod
|
||||
def register_discord_user(user_id: str, server = Urls.API_URL.value) -> str:
|
||||
if server is None:
|
||||
server = Urls.API_URL.value
|
||||
registeredId = requests.post(server + "/api_v2/connection/register", verify=False, json={
|
||||
"x-session-id": user_id
|
||||
}).json()
|
||||
|
||||
return registeredId["discord_id"]
|
||||
23
src/fivemserver/whitelistmanager.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import requests
|
||||
from urllib3 import disable_warnings
|
||||
from urllib3.exceptions import InsecureRequestWarning
|
||||
|
||||
# Supress only InsecureRequestWarning
|
||||
disable_warnings(InsecureRequestWarning)
|
||||
|
||||
WHITELIST_URL_ENDPOINT = f'iswhitelist/'
|
||||
|
||||
class WhiteList:
|
||||
@staticmethod
|
||||
def checkwhitelist(url, discord_user_id: str) -> bool:
|
||||
print('🗒️ Vérification de la whitelist...')
|
||||
|
||||
response = requests.get(url + WHITELIST_URL_ENDPOINT + discord_user_id, verify=False)
|
||||
api_data = response.json()
|
||||
|
||||
if api_data['whitelisted']:
|
||||
print("👍 Vous êtes en whitelist")
|
||||
return True
|
||||
else:
|
||||
print('🙅♂️ Désole mais vous n\'êtes pas whitelisté sur le serveur.')
|
||||
return False
|
||||
95
src/main.py
Normal file
@@ -0,0 +1,95 @@
|
||||
import sys
|
||||
from tools.utils import get_internal_dir
|
||||
|
||||
from PySide6.QtCore import QResource
|
||||
from PySide6.QtGui import QFontDatabase, QFont
|
||||
from PySide6.QtWidgets import QApplication
|
||||
|
||||
# Imports pour la gestion de la configuration
|
||||
from config.config_manager import ConfigManager
|
||||
from config.constants import Resources
|
||||
|
||||
# Imports pour la vérification Discord
|
||||
from discord.discord_tools import CheckDiscord
|
||||
|
||||
# Import pour la partie ui
|
||||
from ui.custom_message_box import CustomMessageBox
|
||||
from ui.main_window import MainWindow
|
||||
|
||||
# Ne pas supprimer ! Enregistre les ressources Qt
|
||||
import resources # noqa: F401 - required to register Qt resources
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Bundle path resolution
|
||||
# ---------------------------------------------------------------------------
|
||||
bundle_dir = get_internal_dir()
|
||||
QResource.registerResource(f"{bundle_dir}/resources.py")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Font helper
|
||||
# ---------------------------------------------------------------------------
|
||||
def load_custom_font() -> str:
|
||||
font_id = QFontDatabase.addApplicationFont(Resources.FONT.value)
|
||||
if font_id == -1:
|
||||
raise RuntimeError("Failed to load font from resources.")
|
||||
font_families = QFontDatabase.applicationFontFamilies(font_id)
|
||||
if not font_families:
|
||||
raise RuntimeError("No font families found in the loaded font.")
|
||||
return font_families[0]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Entry point
|
||||
# ---------------------------------------------------------------------------
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
# 1. Initialisation UNIQUE du gestionnaire de config
|
||||
config = ConfigManager()
|
||||
|
||||
# 2. Setup environnemental (Styles & Fonts)
|
||||
try:
|
||||
with open(f"{bundle_dir}/styles/styles.qss", 'r') as f:
|
||||
app.setStyleSheet(f.read())
|
||||
|
||||
app.setFont(QFont(load_custom_font(), 16))
|
||||
except Exception as e:
|
||||
print(f"Erreur lors du chargement des styles : {e}")
|
||||
|
||||
|
||||
# 3. Garde-fou Discord
|
||||
if not CheckDiscord.isdiscordrunning():
|
||||
msg = CustomMessageBox(
|
||||
title="La Tanière: Discord non détecté",
|
||||
message="Discord ne semble pas lancé.\n\n"
|
||||
"Tu dois avoir démarré Discord et y être connecté pour utiliser l'application.\n\n"
|
||||
"Lorsque cela sera fait, relance le launcher.",
|
||||
icon_type=CustomMessageBox.WARNING,
|
||||
buttons=CustomMessageBox.OK
|
||||
)
|
||||
msg.exec()
|
||||
sys.exit(0) # On quitte proprement sans lancer MainWindow
|
||||
|
||||
# On récupère l'ID stocké (sera "" si absent grâce au schéma)
|
||||
stored_user_id = config.get_discord_user()
|
||||
if stored_user_id != "" and not stored_user_id.isspace():
|
||||
if not CheckDiscord.isuserconnected():
|
||||
msg = CustomMessageBox(
|
||||
title="La Tanière: connexion Discord",
|
||||
message="Tu n'est pas connecté à Discord\n\n"
|
||||
"Assure-toi que tu es connecté à Discord.\n\n"
|
||||
"Lorsque cela sera fait, relance le launcher.",
|
||||
icon_type=CustomMessageBox.WARNING,
|
||||
buttons=CustomMessageBox.OK
|
||||
)
|
||||
msg.exec()
|
||||
sys.exit(0) # On quitte proprement sans lancer MainWindow
|
||||
|
||||
# 4. Lancement de l'application si tout est OK
|
||||
window = MainWindow(bundle_dir, config)
|
||||
# Note: Assure-toi que self.show() est bien dans le __init__ de MainWindow
|
||||
# ou ajoute window.show() ici si tu l'en lèves du constructeur.
|
||||
|
||||
sys.exit(app.exec())
|
||||
181261
src/resources.py
Normal file
27
src/tools/utils.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from PySide6.QtWidgets import QApplication
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
def get_internal_dir() -> Path:
|
||||
# Retourne le chemin vers les ressources figées à l'intérieur de l'EXE (_MEIPASS).
|
||||
# En mode script, retourne le dossier du fichier .py.
|
||||
if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
|
||||
return Path(sys._MEIPASS).resolve()
|
||||
return Path(__file__).resolve().parents[2]
|
||||
|
||||
def get_executable_dir() -> Path:
|
||||
# Retourne le chemin du dossier contenant réellement le fichier .exe.
|
||||
# C'est ici que se trouve votre 'config.json'.
|
||||
if getattr(sys, 'frozen', False):
|
||||
# sys.executable est le chemin complet vers l'application .exe
|
||||
return Path(sys.executable).parent.resolve()
|
||||
return Path(__file__).resolve().parents[2]
|
||||
|
||||
def quit_application(exit_code: int = 0) -> None:
|
||||
app = QApplication.instance()
|
||||
if app is not None:
|
||||
app.closeAllWindows()
|
||||
app.exit(exit_code)
|
||||
sys.exit(exit_code)
|
||||
133
src/ui/custom_message_box.py
Normal file
@@ -0,0 +1,133 @@
|
||||
from PySide6.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout,
|
||||
QLabel, QPushButton, QWidget, QGraphicsDropShadowEffect)
|
||||
from PySide6.QtCore import Qt, QPropertyAnimation, QEasingCurve
|
||||
from PySide6.QtGui import QColor
|
||||
|
||||
|
||||
class CustomMessageBox(QDialog):
|
||||
# Enums pour la configuration
|
||||
INFO = "info"
|
||||
WARNING = "warning"
|
||||
OK = "ok"
|
||||
OK_CANCEL = "ok_cancel"
|
||||
|
||||
def __init__(self, title="Notification", message="", icon_type="info", buttons="ok", parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
# --- CONFIGURATION FENÊTRE ---
|
||||
self.setWindowFlags(Qt.FramelessWindowHint | Qt.Dialog)
|
||||
self.setAttribute(Qt.WA_TranslucentBackground)
|
||||
self.setMinimumWidth(400)
|
||||
|
||||
# --- ANIMATION DE FONDU ---
|
||||
self.setWindowOpacity(0)
|
||||
self.fade_anim = QPropertyAnimation(self, b"windowOpacity")
|
||||
self.fade_anim.setDuration(350)
|
||||
self.fade_anim.setStartValue(0)
|
||||
self.fade_anim.setEndValue(1)
|
||||
self.fade_anim.setEasingCurve(QEasingCurve.OutCubic)
|
||||
|
||||
# --- UI SETUP ---
|
||||
self.container = QWidget(self)
|
||||
self.container.setObjectName("MsgBoxMainContainer")
|
||||
# Utilisé dans le fichier QSS comme condition dynamique de style
|
||||
self.container.setProperty("iconType", icon_type)
|
||||
self.container.setProperty("buttonsType", buttons)
|
||||
|
||||
# LAYOUT PRINCIPAL DU CONTAINER (Marges à 0 pour coller le bouton au bord)
|
||||
layout = QVBoxLayout(self.container)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.setSpacing(0)
|
||||
|
||||
# 1. Barre de titre (Contenu collé en haut et à droite)
|
||||
title_bar_layout = QHBoxLayout()
|
||||
title_bar_layout.setContentsMargins(15, 0, 0, 0)
|
||||
title_bar_layout.setSpacing(0)
|
||||
|
||||
title_label = QLabel(title.upper())
|
||||
title_label.setObjectName("MsgBoxTitleLabel")
|
||||
|
||||
self.close_btn = QPushButton("✕")
|
||||
self.close_btn.setObjectName("MsgBoxCloseButton")
|
||||
self.close_btn.setFixedSize(45, 35)
|
||||
self.close_btn.clicked.connect(self.reject)
|
||||
self.close_btn.setCursor(Qt.PointingHandCursor)
|
||||
|
||||
title_bar_layout.addWidget(title_label)
|
||||
title_bar_layout.addStretch()
|
||||
title_bar_layout.addWidget(self.close_btn)
|
||||
layout.addLayout(title_bar_layout)
|
||||
|
||||
# 2. SOUS-LAYOUT POUR LE CONTENU (Ici on remet des marges pour le texte)
|
||||
body_layout = QVBoxLayout()
|
||||
body_layout.setContentsMargins(20, 10, 20, 20)
|
||||
body_layout.setSpacing(15)
|
||||
|
||||
# Contenu central (Icône + Message)
|
||||
content_layout = QHBoxLayout()
|
||||
icon_label = QLabel()
|
||||
icon_label.setObjectName("MsgBoxIconLabel")
|
||||
icon_text = "ℹ️" if icon_type == self.INFO else "⚠️"
|
||||
icon_label.setText(icon_text)
|
||||
|
||||
msg_label = QLabel(message)
|
||||
msg_label.setObjectName("MsgBoxMessageLabel")
|
||||
msg_label.setWordWrap(True)
|
||||
|
||||
content_layout.addWidget(icon_label)
|
||||
content_layout.addWidget(msg_label, 1)
|
||||
body_layout.addLayout(content_layout)
|
||||
|
||||
# Boutons d'action
|
||||
btn_layout = QHBoxLayout()
|
||||
btn_layout.setSpacing(10)
|
||||
btn_layout.addStretch()
|
||||
|
||||
if buttons == self.OK_CANCEL:
|
||||
self.btn_cancel = QPushButton("ANNULER")
|
||||
self.btn_cancel.setObjectName("MsgBoxCancelButton")
|
||||
self.btn_cancel.clicked.connect(self.reject)
|
||||
btn_layout.addWidget(self.btn_cancel)
|
||||
|
||||
self.btn_ok = QPushButton("COMPRIS")
|
||||
self.btn_ok.setObjectName("MsgBoxOkButton")
|
||||
self.btn_ok.setCursor(Qt.PointingHandCursor)
|
||||
self.btn_ok.clicked.connect(self.accept)
|
||||
btn_layout.addWidget(self.btn_ok)
|
||||
|
||||
body_layout.addLayout(btn_layout)
|
||||
|
||||
# Ajout du body_layout dans le layout principal
|
||||
layout.addLayout(body_layout)
|
||||
|
||||
# --- OMBRE PORTÉE ---
|
||||
shadow = QGraphicsDropShadowEffect(self)
|
||||
shadow.setBlurRadius(20)
|
||||
shadow.setXOffset(0)
|
||||
shadow.setYOffset(8)
|
||||
shadow.setColor(QColor(0, 0, 0, 180))
|
||||
self.container.setGraphicsEffect(shadow)
|
||||
|
||||
final_layout = QVBoxLayout(self)
|
||||
final_layout.addWidget(self.container)
|
||||
|
||||
self.old_pos = None
|
||||
|
||||
def showEvent(self, event):
|
||||
super().showEvent(event)
|
||||
self.fade_anim.start()
|
||||
|
||||
def mousePressEvent(self, e):
|
||||
# On permet le déplacement uniquement si on clique sur la barre de titre
|
||||
# ou n'importe où sauf sur les boutons
|
||||
if e.button() == Qt.LeftButton:
|
||||
self.old_pos = e.globalPosition().toPoint()
|
||||
|
||||
def mouseMoveEvent(self, e):
|
||||
if self.old_pos:
|
||||
delta = e.globalPosition().toPoint() - self.old_pos
|
||||
self.move(self.x() + delta.x(), self.y() + delta.y())
|
||||
self.old_pos = e.globalPosition().toPoint()
|
||||
|
||||
def mouseReleaseEvent(self, e):
|
||||
self.old_pos = None
|
||||
75
src/ui/hazard_stripes.py
Normal file
@@ -0,0 +1,75 @@
|
||||
# ui/hazard_stripes.py
|
||||
|
||||
from PySide6.QtWidgets import QPushButton, QStyleOptionButton, QStyle
|
||||
from PySide6.QtGui import QPainter, QColor, QPainterPath, QPen, QPolygon
|
||||
from PySide6.QtCore import Qt, QPoint
|
||||
|
||||
|
||||
class HazardButton(QPushButton):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self._hazard = False
|
||||
|
||||
def set_hazard(self, enabled: bool):
|
||||
self._hazard = enabled
|
||||
self.update()
|
||||
|
||||
def paintEvent(self, event):
|
||||
if not hasattr(self, '_hazard'):
|
||||
self.__dict__['_hazard'] = False
|
||||
|
||||
p = QPainter(self)
|
||||
p.setRenderHint(QPainter.RenderHint.Antialiasing)
|
||||
|
||||
r = self.rect()
|
||||
radius = 4
|
||||
|
||||
path = QPainterPath()
|
||||
path.addRoundedRect(r, radius, radius)
|
||||
p.setClipPath(path)
|
||||
|
||||
if self._hazard:
|
||||
p.fillRect(r, QColor("#FFD700"))
|
||||
|
||||
p.setPen(Qt.PenStyle.NoPen)
|
||||
p.setBrush(QColor("#000000"))
|
||||
|
||||
stripe_width = 20
|
||||
stripe_gap = 30
|
||||
period = stripe_width + stripe_gap
|
||||
diag = r.width() + r.height()
|
||||
|
||||
for x in range(-diag, diag * 2, period):
|
||||
stripe = QPolygon([
|
||||
QPoint(x, r.bottom() + 10),
|
||||
QPoint(x + stripe_width, r.bottom() + 10),
|
||||
QPoint(x + stripe_width + r.height() + 10, r.top() - 10),
|
||||
QPoint(x + r.height() + 10, r.top() - 10),
|
||||
])
|
||||
p.drawPolygon(stripe)
|
||||
|
||||
# ↓ Fond semi-transparent derrière le texte
|
||||
text_bg = QColor(255, 215, 0, 230) # noir à 63% d'opacité
|
||||
p.setPen(Qt.PenStyle.NoPen)
|
||||
p.setBrush(text_bg)
|
||||
bg_rect = r.adjusted(60, 8, -60, -8) # marges internes
|
||||
p.drawRoundedRect(bg_rect, 4, 4)
|
||||
|
||||
else:
|
||||
p.fillRect(r, QColor("#FFD700"))
|
||||
|
||||
p.setClipping(False)
|
||||
p.setPen(QPen(QColor("#000000"), 2))
|
||||
p.setBrush(Qt.BrushStyle.NoBrush)
|
||||
p.drawRoundedRect(r.adjusted(1, 1, -1, -1), radius, radius)
|
||||
|
||||
p.setClipping(False)
|
||||
opt = QStyleOptionButton()
|
||||
self.initStyleOption(opt)
|
||||
opt.palette.setColor(
|
||||
opt.palette.ColorRole.ButtonText,
|
||||
self.palette().color(self.palette().ColorRole.ButtonText)
|
||||
)
|
||||
self.style().drawControl(
|
||||
QStyle.ControlElement.CE_PushButtonLabel, opt, p, self
|
||||
)
|
||||
167
src/ui/main_window.py
Normal file
@@ -0,0 +1,167 @@
|
||||
import webbrowser
|
||||
from sys import platform
|
||||
from os import environ
|
||||
|
||||
from PySide6 import QtGui
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtUiTools import QUiLoader
|
||||
from PySide6.QtWidgets import QMainWindow, QSizePolicy
|
||||
|
||||
from config.config_manager import ConfigManager
|
||||
from config.constants import NO_STAFF, Urls, NO_WHITELIST
|
||||
from ui.custom_message_box import CustomMessageBox
|
||||
from ui.hazard_stripes import HazardButton
|
||||
from controllers.audio_controller import AudioController
|
||||
from controllers.glow_animator import GlowAnimator
|
||||
from controllers.window_dragger import WindowDragger
|
||||
from discord import discord_oauth
|
||||
from tools.utils import quit_application
|
||||
|
||||
from fake_patch_notes import patch_note
|
||||
|
||||
# For Linux Wayland to authorize moving window
|
||||
if platform.startswith('linux'):
|
||||
environ["QT_QPA_PLATFORM"] = "xcb"
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self, bundle_dir: str, config_manager: ConfigManager):
|
||||
super().__init__()
|
||||
|
||||
self.config = config_manager
|
||||
|
||||
# UI
|
||||
self.ui = QUiLoader().load(f"{bundle_dir}/ui/mainwindow_vertical_pager.ui", self)
|
||||
self.setCentralWidget(self.ui.centralWidget())
|
||||
self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.Window)
|
||||
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
|
||||
|
||||
# Test bouton en contruction
|
||||
en_chantier = True
|
||||
if en_chantier:
|
||||
old_btn = self.ui.connexion_btn
|
||||
parent_layout = self.ui.verticalLayout_6 # layout direct du bouton dans le .ui
|
||||
|
||||
index = parent_layout.indexOf(old_btn)
|
||||
|
||||
new_btn = HazardButton(old_btn.parentWidget())
|
||||
new_btn.setObjectName("connexion_btn")
|
||||
new_btn.setText("EN MAINTENANCE")
|
||||
new_btn.setIcon(old_btn.icon())
|
||||
new_btn.setIconSize(old_btn.iconSize())
|
||||
new_btn.setMinimumSize(old_btn.minimumSize())
|
||||
new_btn.set_hazard(True)
|
||||
|
||||
parent_layout.takeAt(index)
|
||||
old_btn.deleteLater()
|
||||
parent_layout.insertWidget(index, new_btn)
|
||||
|
||||
self.ui.connexion_btn = new_btn
|
||||
self.ui.connexion_btn.clicked.connect(self._on_connexion)
|
||||
|
||||
# centrage vertical du bouton connexion
|
||||
if NO_STAFF:
|
||||
self.ui.staff_btn.hide()
|
||||
layout = self.ui.verticalLayout_6
|
||||
# Trouver et modifier le spacer item
|
||||
for i in range(layout.count()):
|
||||
item = layout.itemAt(i)
|
||||
if item.spacerItem(): # C'est un spacer
|
||||
item.spacerItem().changeSize(20, 15, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
|
||||
layout.invalidate() # Forcer le recalcul du layout
|
||||
break
|
||||
# self.ui.spacer_substitution.hide()
|
||||
|
||||
if config_manager.get_discord_user() == "" or config_manager.get_discord_user().isspace():
|
||||
self.ui.queue_lbl.hide()
|
||||
self.ui.queue_position.hide()
|
||||
self.ui.stackedWidget.setCurrentIndex(1)
|
||||
|
||||
self.ui.info_text.setMarkdown(patch_note)
|
||||
|
||||
# Sous-systèmes
|
||||
self._audio = AudioController(self.config, self.ui.audio_volume_adjust, self.ui.mute_btn)
|
||||
self._glow = GlowAnimator(self.ui.connexion_btn)
|
||||
self._dragger = WindowDragger(self)
|
||||
|
||||
self._connect_signals()
|
||||
self._center_window()
|
||||
self.show()
|
||||
|
||||
if NO_WHITELIST:
|
||||
msg = CustomMessageBox(
|
||||
title="La Tanière: Non whitelisté",
|
||||
message="\n\nTu n'est pas whitelisté sur le serveur\n\n"
|
||||
"Assure-toi de te faire whitelister.\n\n"
|
||||
"Lorsque cela sera fait, relance le launcher.",
|
||||
icon_type=CustomMessageBox.WARNING,
|
||||
buttons=CustomMessageBox.OK
|
||||
)
|
||||
msg.exec()
|
||||
quit_application()
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Setup
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _connect_signals(self) -> None:
|
||||
self.ui.close_btn.clicked.connect(self.close)
|
||||
self.ui.minimize_btn.clicked.connect(self.showMinimized)
|
||||
self.ui.connexion_btn.clicked.connect(self._on_connexion)
|
||||
self.ui.discord_btn.clicked.connect(self._on_discord)
|
||||
self.ui.intranet_btn.clicked.connect(self._on_intranet)
|
||||
|
||||
self.ui.discord_auth_btn.clicked.connect(self._on_discord_auth_btn)
|
||||
|
||||
def _center_window(self) -> None:
|
||||
self.adjustSize()
|
||||
screen = (
|
||||
QtGui.QGuiApplication.screenAt(QtGui.QCursor.pos())
|
||||
or QtGui.QGuiApplication.primaryScreen()
|
||||
)
|
||||
rect = self.frameGeometry()
|
||||
rect.moveCenter(screen.availableGeometry().center())
|
||||
self.move(rect.topLeft())
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Button handlers
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _on_connexion(self) -> None:
|
||||
pass # à implémenter
|
||||
|
||||
@staticmethod
|
||||
def _on_discord() -> None:
|
||||
webbrowser.open(Urls.DISCORD.value)
|
||||
|
||||
def _on_intranet(self) -> None:
|
||||
webbrowser.open(Urls.INTRANET.value)
|
||||
self._glow.start()
|
||||
|
||||
def _on_discord_auth_btn(self) -> None:
|
||||
self.config.set_discord_user(discord_oauth.get_discord_user_id())
|
||||
self.config.save()
|
||||
self.ui.stackedWidget.setCurrentIndex(0)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Mouse events → délégués au WindowDragger
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def mousePressEvent(self, event: QtGui.QMouseEvent) -> None:
|
||||
self._dragger.mouse_press(event)
|
||||
super().mousePressEvent(event)
|
||||
|
||||
def mouseMoveEvent(self, event: QtGui.QMouseEvent) -> None:
|
||||
self._dragger.mouse_move(event)
|
||||
super().mouseMoveEvent(event)
|
||||
|
||||
def mouseReleaseEvent(self, event: QtGui.QMouseEvent) -> None:
|
||||
self._dragger.mouse_release(event)
|
||||
super().mouseReleaseEvent(event)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Close
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def closeEvent(self, event) -> None:
|
||||
self.config.save()
|
||||
super().closeEvent(event)
|
||||
98
styles.qss
@@ -1,98 +0,0 @@
|
||||
QPushButton#connexion_btn {
|
||||
border-radius: 15px;
|
||||
background-color: rgb(255, 120, 0);
|
||||
}
|
||||
|
||||
|
||||
QPushButton#connexion_btn:hover {
|
||||
background: #ffad66;
|
||||
}
|
||||
|
||||
QPushButton#discord_btn,
|
||||
QPushButton#intranet_btn
|
||||
{
|
||||
border-radius: 15px;
|
||||
background-color: #203a43;
|
||||
}
|
||||
|
||||
QPushButton#close_btn {
|
||||
border : 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QPushButton#minimize_btn {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-bottom: 5px solid white;
|
||||
color: white;
|
||||
font-size: 18px;
|
||||
padding: 0px;
|
||||
padding-top: 0
|
||||
}
|
||||
|
||||
QTextEdit#info_text {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/*
|
||||
QSlider::groove:horizontal {
|
||||
border: 1px solid #262626;
|
||||
height: 10px;
|
||||
}
|
||||
QSlider::handle:horizontal {
|
||||
background: rgb(236, 127, 43);
|
||||
border: 1px solid rgb(236, 127, 43);
|
||||
width: 23px;
|
||||
border-radius: 3px;
|
||||
height: 100px;
|
||||
margin: -24px -12px;
|
||||
}
|
||||
|
||||
QSlider::sub-page:horizontal{
|
||||
border:0px;
|
||||
border-radius:6px;
|
||||
background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 #12b9ff, stop: 1.0 #015eea);
|
||||
}
|
||||
|
||||
QSlider::add-page:horizontal{
|
||||
border:0px;
|
||||
border-radius:6px;
|
||||
background:qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,stop: 0 rgb(146, 149, 150), stop: 1.0 rgb(253, 254, 254));
|
||||
}
|
||||
*/
|
||||
|
||||
QSlider::groove:horizontal {
|
||||
border: 1px inset #1C1C1C;
|
||||
height: 6px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
QSlider::groove:horizontal {
|
||||
border: 1px inset #1C1C1C;
|
||||
height: 6px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
QSlider::sub-page:horizontal {
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #12b9ff, stop: 1.0 #015eea);
|
||||
border: 1px inset #1C1C1C;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* groove background on right of slider */
|
||||
QSlider::add-page:horizontal {
|
||||
background: #7D7D7D;
|
||||
border: 1px outset #1C1C1C;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
QSlider::handle:horizontal {
|
||||
background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 rgb(241, 160, 61), stop:1 rgb(233, 111, 29));
|
||||
border: 1px solid rgb(213, 125, 2);
|
||||
width: 12px;
|
||||
height: 10px;
|
||||
margin-top: -8px;
|
||||
margin-bottom: -8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
315
styles/styles.qss
Normal file
@@ -0,0 +1,315 @@
|
||||
QLabel {
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
#main_container {
|
||||
border-radius: 30px;
|
||||
background: qradialgradient(cx:0.5, cy:0.5, radius:0.8, fx:0.5, fy:0.5,
|
||||
stop: 0 #16213e,
|
||||
stop: 1 #0a0e14);
|
||||
}
|
||||
|
||||
QFrame#logo_frame {
|
||||
background-image: url(:/assets/logo.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
QFrame#frame_2 QLabel {
|
||||
color: rgb(163, 177, 198);
|
||||
}
|
||||
|
||||
QFrame#frame_2 QLabel#discord_title_label {
|
||||
font-size: 28px;
|
||||
color: rgb(255, 255, 255) /* label enfant, obligé de définir la couleur car ne prend pas la général */
|
||||
}
|
||||
|
||||
QFrame#frame_2 QLabel#label_2 {
|
||||
/* font-family: 'sans serif'; */
|
||||
}
|
||||
|
||||
QLabel#maintitle_label {
|
||||
font-size: 38px;
|
||||
}
|
||||
|
||||
QLabel#subtitle_label {
|
||||
color: rgb(163, 177, 198);
|
||||
}
|
||||
|
||||
QLabel#queue_position {
|
||||
font-size: 36px;
|
||||
color: rgb(17, 248, 183);
|
||||
}
|
||||
|
||||
QLabel#queue_lbl {
|
||||
|
||||
}
|
||||
|
||||
QPushButton#connexion_btn[chantier="false"] {
|
||||
/* Dégradé chaleureux : Orange vers Orange-Rouge */
|
||||
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
|
||||
stop: 0 #ff9d00,
|
||||
stop: 1 #f56100);
|
||||
|
||||
border-radius: 12px;
|
||||
border: 1px solid #b34700;
|
||||
color: white;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
QPushButton#connexion_btn[chantier="false"]:hover {
|
||||
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
|
||||
stop: 0 #ffb338,
|
||||
stop: 1 #ff7a29);
|
||||
border: 1px solid #ffcc80;
|
||||
/* Un léger halo autour du bouton */
|
||||
outline: none;
|
||||
}
|
||||
|
||||
QPushButton#connexion_btn[chantier="false"]:pressed {
|
||||
background: #cc5200;
|
||||
padding-top: 12px; /* Effet d'enfoncement */
|
||||
}
|
||||
|
||||
/* État normal - Rouge Corail Vibrant */
|
||||
QPushButton#staff_btn {
|
||||
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
|
||||
stop:0 #FF4B2B, stop:1 #FF416C);
|
||||
color: white;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #d03522;
|
||||
padding: 5px 15px;
|
||||
}
|
||||
|
||||
HazardButton#connexion_btn {
|
||||
color: #0A1A3A;
|
||||
/* color: #0D2A6B;*/
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
HazardButton#connexion_btn:hover {
|
||||
/* color: #ffffff;*/
|
||||
color: #0D2A6B;
|
||||
}
|
||||
|
||||
HazardButton#connexion_btn:pressed {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
QPushButton#staff_btn:hover {
|
||||
background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
|
||||
stop:0 #FF6046, stop:1 #FF527B);
|
||||
border: 1px solid #FF4B2B;
|
||||
}
|
||||
|
||||
QPushButton#staff_btn:pressed
|
||||
{
|
||||
background-color: #d03522;
|
||||
padding-top: 7px;
|
||||
padding-left: 17px;
|
||||
}
|
||||
|
||||
QPushButton#discord_btn,
|
||||
QPushButton#discord_auth_btn,
|
||||
QPushButton#intranet_btn
|
||||
{
|
||||
background-color: rgba(32, 58, 67, 0.6); /* Bleu très sombre semi-transparent */
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
border-radius: 8px;
|
||||
color: #e2e8f0;
|
||||
font-weight: bold;
|
||||
padding: 8px 15px;
|
||||
}
|
||||
|
||||
QPushButton#discord_btn:hover,
|
||||
QPushButton#discord_auth_btn:hover
|
||||
{
|
||||
background-color: rgba(88, 101, 242, 0.4); /* Fond bleu Discord translucide */
|
||||
border: 2px solid #7289da; /* Bordure plus épaisse et claire pour l'éclat */
|
||||
color: white;
|
||||
}
|
||||
|
||||
QPushButton#intranet_btn:hover {
|
||||
background-color: rgba(0, 242, 255, 0.15); /* Teinte turquoise légère en fond */
|
||||
border: 2px solid #00f2ff; /* Bordure turquoise vive et épaisse */
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
QPushButton#discord_btn:pressed,
|
||||
QPushButton#discord_auth_btn:pressed,
|
||||
QPushButton#intranet_btn:pressed
|
||||
{
|
||||
background-color: #0f172a;
|
||||
padding-top: 10px; /* Petit effet d'enfoncement */
|
||||
}
|
||||
|
||||
QPushButton#mute_btn {
|
||||
border-radius: 15px;
|
||||
background-color: rgb(255, 120, 0);
|
||||
}
|
||||
|
||||
QPushButton#mute_btn[muted="true"] {
|
||||
background-color: rgb(200, 0, 0);
|
||||
}
|
||||
|
||||
QPushButton#mute_btn:hover {
|
||||
background-color: rgb(255, 150, 40);
|
||||
}
|
||||
|
||||
QPushButton#close_btn {
|
||||
border : 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QPushButton#minimize_btn {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-bottom: 5px solid white;
|
||||
color: white;
|
||||
font-size: 18px;
|
||||
padding: 0px;
|
||||
padding-top: 0
|
||||
}
|
||||
|
||||
QFrame#info_frame{
|
||||
background: qlineargradient(
|
||||
x1:0, y1:0,
|
||||
x2:0, y2:1,
|
||||
stop:0 rgba(255,255,255,30),
|
||||
stop:1 rgba(255,255,255,30)
|
||||
);
|
||||
border-radius: 20px;
|
||||
border: 1px solid rgba(255,255,255,140);
|
||||
}
|
||||
|
||||
QTextEdit#info_text {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
QSlider {
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
QSlider::groove:horizontal {
|
||||
border: 1px solid #1C1C1C;
|
||||
height: 8px;
|
||||
background: #7D7D7D;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QSlider::sub-page:horizontal {
|
||||
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #12b9ff, stop: 1.0 #015eea);
|
||||
border: 1px solid #1C1C1C;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QSlider::handle:horizontal {
|
||||
background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FF8C00, stop:1 #FF5E00);
|
||||
border: 1px solid #B34700;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: -5px 0; /* Ajusté pour centrer 16px sur barre de 8px */
|
||||
border-radius: 8px; /* Moitié exacte de width/height */
|
||||
}
|
||||
|
||||
/* On répète les propriétés cruciales pour les états survolés/pressés */
|
||||
QSlider::handle:horizontal:hover {
|
||||
background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFA500, stop:1 #FF7F00);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
QSlider::handle:horizontal:pressed {
|
||||
background: #E65100;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------
|
||||
Custom Message Box
|
||||
----------------------------------------------*/
|
||||
|
||||
QWidget#MsgBoxMainContainer {
|
||||
border-radius: 15px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
QWidget#MsgBoxMainContainer[iconType="info"] {
|
||||
background: qlineargradient(
|
||||
x1: 0, y1: 0, x2: 1, y2: 1,
|
||||
stop: 0 #101624,
|
||||
stop: 1 #248277
|
||||
);
|
||||
}
|
||||
|
||||
QWidget#MsgBoxMainContainer[iconType="warning"] {
|
||||
background: qlineargradient(
|
||||
x1: 0, y1: 0, x2: 1, y2: 1,
|
||||
stop: 0 #101624,
|
||||
stop: 1 #cf5b16
|
||||
);
|
||||
}
|
||||
|
||||
QWidget#MsgBoxMainContainer QLabel,
|
||||
QWidget#MsgBoxMainContainer QPushButton
|
||||
{
|
||||
color: white;
|
||||
/*font-size: 18px;
|
||||
/* font-family: 'Segoe UI';*/
|
||||
}
|
||||
|
||||
QPushButton#MsgBoxOkButton,
|
||||
QPushButton#MsgBoxCancelButton {
|
||||
border-radius: 6px;
|
||||
/* color: white;*/
|
||||
padding: 8px 20px;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
border: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
|
||||
QPushButton#MsgBoxOkButton {
|
||||
background: #248277;
|
||||
}
|
||||
|
||||
QPushButton#MsgBoxCancelButton {
|
||||
background: #2a313d;
|
||||
}
|
||||
|
||||
QPushButton#MsgBoxOkButton:hover,
|
||||
QPushButton#MsgBoxCancelButton:hover{
|
||||
background: #363d4a;
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
QPushButton#MsgBoxCloseButton {
|
||||
background: transparent;
|
||||
color: white;
|
||||
border: none;
|
||||
font-size: 14px;
|
||||
/* Rayon identique au container (15px) pour épouser parfaitement le coin */
|
||||
border-top-right-radius: 15px;
|
||||
border-bottom-left-radius: 10px;
|
||||
}
|
||||
|
||||
QPushButton#MsgBoxCloseButton:hover {
|
||||
background-color: #e74c3c;
|
||||
color: white;
|
||||
}
|
||||
|
||||
QLabel#MsgBoxTitleLabel {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
color: rgba(255,255,255,0.7);
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
QLabel#MsgBoxMessageLabel {
|
||||
font-size: 14px;
|
||||
color: #f0f0f0;
|
||||
}
|
||||
|
||||
QLabel#MsgBoxIconLabel {
|
||||
font-size: 35px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
@@ -38,12 +38,9 @@
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="resources.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/assets/Icone.ico</normaloff>:/assets/Icone.ico</iconset>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">color: rgb(255, 255, 255);</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="main_container">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
@@ -57,14 +54,6 @@
|
||||
<height>703</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">#main_container {
|
||||
border-radius: 30px;
|
||||
background-image: url(:/assets/background.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
@@ -189,7 +178,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<iconset resource="../resources.qrc">
|
||||
<normaloff>:/assets/system-shutdown.png</normaloff>:/assets/system-shutdown.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@@ -292,7 +281,7 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<widget class="QFrame" name="logo_frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
@@ -359,37 +348,25 @@
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<widget class="QLabel" name="queue_lbl">
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Position en file d'attente: </string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLCDNumber" name="lcdNumber">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>70</width>
|
||||
<height>50</height>
|
||||
</size>
|
||||
<widget class="QLabel" name="queue_position">
|
||||
<property name="text">
|
||||
<string>20</string>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LayoutDirection::RightToLeft</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Sunken</enum>
|
||||
</property>
|
||||
<property name="smallDecimalPoint">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="digitCount">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="value" stdset="0">
|
||||
<double>20.000000000000000</double>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -446,7 +423,7 @@
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QSlider" name="horizontalSlider">
|
||||
<widget class="QSlider" name="audio_volume_adjust">
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
@@ -465,12 +442,22 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<widget class="QPushButton" name="mute_btn">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="QIcon::ThemeIcon::AudioVolumeHigh"/>
|
||||
<iconset resource="../resources.qrc">
|
||||
<normaloff>:/assets/sound-speaker.svg</normaloff>:/assets/sound-speaker.svg</iconset>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -577,7 +564,7 @@
|
||||
<item alignment="Qt::AlignmentFlag::AlignHCenter">
|
||||
<widget class="QLabel" name="maintitle_label">
|
||||
<property name="text">
|
||||
<string>la taniere</string>
|
||||
<string>LA TANIÈRE</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -606,7 +593,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>un espace pour se retrouver</string>
|
||||
<string>Un espace pour se retrouver</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::TextFormat::AutoText</enum>
|
||||
@@ -682,7 +669,17 @@
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>connexion</string>
|
||||
<string> Connexion</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources.qrc">
|
||||
<normaloff>:/assets/padlock-lock.svg</normaloff>:/assets/padlock-lock.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -713,6 +710,16 @@
|
||||
<property name="text">
|
||||
<string>staff</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources.qrc">
|
||||
<normaloff>:/assets/tools-repair.svg</normaloff>:/assets/tools-repair.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -754,7 +761,17 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>discord</string>
|
||||
<string> Discord</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources.qrc">
|
||||
<normaloff>:/assets/discord-icon.svg</normaloff>:/assets/discord-icon.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -780,7 +797,17 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>intranet</string>
|
||||
<string> Intranet</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources.qrc">
|
||||
<normaloff>:/assets/computer-tv.svg</normaloff>:/assets/computer-tv.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -839,16 +866,7 @@
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QFrame#info_frame{
|
||||
background: qlineargradient(
|
||||
x1:0, y1:0,
|
||||
x2:0, y2:1,
|
||||
stop:0 rgba(255,255,255,30),
|
||||
stop:1 rgba(255,255,255,30)
|
||||
);
|
||||
border-radius: 20px;
|
||||
border: 1px solid rgba(255,255,255,140);
|
||||
}</string>
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
@@ -862,6 +880,9 @@
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::TextInteractionFlag::NoTextInteraction</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -890,7 +911,7 @@
|
||||
</widget>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="resources.qrc"/>
|
||||
<include location="../resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
395
ui/mainwindow_ui.py
Normal file
@@ -0,0 +1,395 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'mainwindowdJHBSQ.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.10.2
|
||||
##
|
||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||
################################################################################
|
||||
|
||||
import resources_rc
|
||||
from PySide6.QtCore import (QCoreApplication, QMetaObject, QSize, Qt)
|
||||
from PySide6.QtGui import (QIcon)
|
||||
from PySide6.QtWidgets import (QFrame, QHBoxLayout, QLabel,
|
||||
QPushButton, QSizePolicy, QSlider,
|
||||
QSpacerItem, QTextEdit, QVBoxLayout, QWidget)
|
||||
|
||||
|
||||
class Ui_MainWindow(object):
|
||||
def setupUi(self, MainWindow):
|
||||
if not MainWindow.objectName():
|
||||
MainWindow.setObjectName(u"MainWindow")
|
||||
MainWindow.setWindowModality(Qt.WindowModality.ApplicationModal)
|
||||
MainWindow.resize(1199, 703)
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
|
||||
MainWindow.setSizePolicy(sizePolicy)
|
||||
MainWindow.setMinimumSize(QSize(1199, 703))
|
||||
MainWindow.setMaximumSize(QSize(1199, 703))
|
||||
MainWindow.setContextMenuPolicy(Qt.ContextMenuPolicy.NoContextMenu)
|
||||
icon = QIcon()
|
||||
icon.addFile(u":/assets/Icone.ico", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
MainWindow.setWindowIcon(icon)
|
||||
self.main_container = QWidget(MainWindow)
|
||||
self.main_container.setObjectName(u"main_container")
|
||||
self.main_container.setMinimumSize(QSize(1199, 703))
|
||||
self.main_container.setMaximumSize(QSize(1199, 703))
|
||||
self.verticalLayout = QVBoxLayout(self.main_container)
|
||||
self.verticalLayout.setSpacing(0)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
|
||||
self.title_bar = QFrame(self.main_container)
|
||||
self.title_bar.setObjectName(u"title_bar")
|
||||
self.title_bar.setMinimumSize(QSize(1199, 50))
|
||||
self.title_bar.setMaximumSize(QSize(1199, 50))
|
||||
self.title_bar.setFrameShape(QFrame.Shape.NoFrame)
|
||||
self.title_bar.setFrameShadow(QFrame.Shadow.Raised)
|
||||
self.horizontalLayout = QHBoxLayout(self.title_bar)
|
||||
self.horizontalLayout.setSpacing(0)
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.horizontalLayout.setContentsMargins(0, 9, 0, 0)
|
||||
self.horizontalSpacer = QSpacerItem(1006, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout.addItem(self.horizontalSpacer)
|
||||
|
||||
self.minimize_btn = QPushButton(self.title_bar)
|
||||
self.minimize_btn.setObjectName(u"minimize_btn")
|
||||
self.minimize_btn.setMinimumSize(QSize(0, 0))
|
||||
self.minimize_btn.setMaximumSize(QSize(25, 25))
|
||||
self.minimize_btn.setStyleSheet(u"")
|
||||
self.minimize_btn.setIconSize(QSize(32, 32))
|
||||
|
||||
self.horizontalLayout.addWidget(self.minimize_btn)
|
||||
|
||||
self.horizontalSpacer_2 = QSpacerItem(20, 20, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout.addItem(self.horizontalSpacer_2)
|
||||
|
||||
self.close_btn = QPushButton(self.title_bar)
|
||||
self.close_btn.setObjectName(u"close_btn")
|
||||
self.close_btn.setMaximumSize(QSize(42, 42))
|
||||
self.close_btn.setStyleSheet(u"")
|
||||
icon1 = QIcon()
|
||||
icon1.addFile(u":/assets/system-shutdown.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.close_btn.setIcon(icon1)
|
||||
self.close_btn.setIconSize(QSize(32, 32))
|
||||
|
||||
self.horizontalLayout.addWidget(self.close_btn)
|
||||
|
||||
self.horizontalSpacer_3 = QSpacerItem(30, 20, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout.addItem(self.horizontalSpacer_3)
|
||||
|
||||
|
||||
self.verticalLayout.addWidget(self.title_bar)
|
||||
|
||||
self.frame_2 = QFrame(self.main_container)
|
||||
self.frame_2.setObjectName(u"frame_2")
|
||||
self.frame_2.setMinimumSize(QSize(1199, 0))
|
||||
self.frame_2.setMaximumSize(QSize(1199, 658))
|
||||
self.frame_2.setFrameShape(QFrame.Shape.NoFrame)
|
||||
self.frame_2.setFrameShadow(QFrame.Shadow.Raised)
|
||||
self.horizontalLayout_2 = QHBoxLayout(self.frame_2)
|
||||
self.horizontalLayout_2.setSpacing(0)
|
||||
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
|
||||
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||
self.left_column = QFrame(self.frame_2)
|
||||
self.left_column.setObjectName(u"left_column")
|
||||
self.left_column.setMinimumSize(QSize(450, 630))
|
||||
self.left_column.setMaximumSize(QSize(450, 630))
|
||||
self.left_column.setFrameShape(QFrame.Shape.NoFrame)
|
||||
self.left_column.setFrameShadow(QFrame.Shadow.Raised)
|
||||
self.verticalLayout_5 = QVBoxLayout(self.left_column)
|
||||
self.verticalLayout_5.setSpacing(0)
|
||||
self.verticalLayout_5.setObjectName(u"verticalLayout_5")
|
||||
self.verticalLayout_5.setContentsMargins(0, 0, 0, 0)
|
||||
self.frame = QFrame(self.left_column)
|
||||
self.frame.setObjectName(u"frame")
|
||||
self.frame.setFrameShape(QFrame.Shape.NoFrame)
|
||||
self.frame.setFrameShadow(QFrame.Shadow.Raised)
|
||||
|
||||
self.verticalLayout_5.addWidget(self.frame)
|
||||
|
||||
self.frame_3 = QFrame(self.left_column)
|
||||
self.frame_3.setObjectName(u"frame_3")
|
||||
sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
|
||||
sizePolicy1.setHorizontalStretch(0)
|
||||
sizePolicy1.setVerticalStretch(0)
|
||||
sizePolicy1.setHeightForWidth(self.frame_3.sizePolicy().hasHeightForWidth())
|
||||
self.frame_3.setSizePolicy(sizePolicy1)
|
||||
self.frame_3.setMinimumSize(QSize(0, 100))
|
||||
self.frame_3.setFrameShape(QFrame.Shape.NoFrame)
|
||||
self.frame_3.setFrameShadow(QFrame.Shadow.Raised)
|
||||
self.horizontalLayout_6 = QHBoxLayout(self.frame_3)
|
||||
self.horizontalLayout_6.setSpacing(0)
|
||||
self.horizontalLayout_6.setObjectName(u"horizontalLayout_6")
|
||||
self.horizontalLayout_6.setContentsMargins(0, 0, 0, 0)
|
||||
self.frame_5 = QFrame(self.frame_3)
|
||||
self.frame_5.setObjectName(u"frame_5")
|
||||
sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
|
||||
sizePolicy2.setHorizontalStretch(0)
|
||||
sizePolicy2.setVerticalStretch(0)
|
||||
sizePolicy2.setHeightForWidth(self.frame_5.sizePolicy().hasHeightForWidth())
|
||||
self.frame_5.setSizePolicy(sizePolicy2)
|
||||
self.frame_5.setMinimumSize(QSize(0, 0))
|
||||
self.frame_5.setFrameShape(QFrame.Shape.NoFrame)
|
||||
self.frame_5.setFrameShadow(QFrame.Shadow.Raised)
|
||||
self.horizontalLayout_8 = QHBoxLayout(self.frame_5)
|
||||
self.horizontalLayout_8.setObjectName(u"horizontalLayout_8")
|
||||
self.queue_lbl = QLabel(self.frame_5)
|
||||
self.queue_lbl.setObjectName(u"queue_lbl")
|
||||
self.queue_lbl.setAutoFillBackground(False)
|
||||
self.queue_lbl.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.horizontalLayout_8.addWidget(self.queue_lbl)
|
||||
|
||||
self.queue_position = QLabel(self.frame_5)
|
||||
self.queue_position.setObjectName(u"queue_position")
|
||||
self.queue_position.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.horizontalLayout_8.addWidget(self.queue_position)
|
||||
|
||||
self.horizontalSpacer_5 = QSpacerItem(80, 20, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_8.addItem(self.horizontalSpacer_5)
|
||||
|
||||
|
||||
self.horizontalLayout_6.addWidget(self.frame_5)
|
||||
|
||||
|
||||
self.verticalLayout_5.addWidget(self.frame_3)
|
||||
|
||||
self.frame_4 = QFrame(self.left_column)
|
||||
self.frame_4.setObjectName(u"frame_4")
|
||||
sizePolicy1.setHeightForWidth(self.frame_4.sizePolicy().hasHeightForWidth())
|
||||
self.frame_4.setSizePolicy(sizePolicy1)
|
||||
self.frame_4.setMinimumSize(QSize(0, 0))
|
||||
self.frame_4.setMaximumSize(QSize(16777215, 50))
|
||||
self.frame_4.setStyleSheet(u"")
|
||||
self.frame_4.setFrameShape(QFrame.Shape.NoFrame)
|
||||
self.frame_4.setFrameShadow(QFrame.Shadow.Raised)
|
||||
self.horizontalLayout_7 = QHBoxLayout(self.frame_4)
|
||||
self.horizontalLayout_7.setObjectName(u"horizontalLayout_7")
|
||||
self.horizontalSlider = QSlider(self.frame_4)
|
||||
self.horizontalSlider.setObjectName(u"horizontalSlider")
|
||||
self.horizontalSlider.setAutoFillBackground(False)
|
||||
self.horizontalSlider.setStyleSheet(u"")
|
||||
self.horizontalSlider.setValue(20)
|
||||
self.horizontalSlider.setOrientation(Qt.Orientation.Horizontal)
|
||||
self.horizontalSlider.setInvertedAppearance(False)
|
||||
|
||||
self.horizontalLayout_7.addWidget(self.horizontalSlider)
|
||||
|
||||
self.volume_btn = QPushButton(self.frame_4)
|
||||
self.volume_btn.setObjectName(u"volume_btn")
|
||||
self.volume_btn.setMinimumSize(QSize(32, 32))
|
||||
icon2 = QIcon()
|
||||
icon2.addFile(u":/assets/sound-speaker.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.volume_btn.setIcon(icon2)
|
||||
self.volume_btn.setFlat(True)
|
||||
|
||||
self.horizontalLayout_7.addWidget(self.volume_btn)
|
||||
|
||||
self.horizontalSpacer_10 = QSpacerItem(180, 20, QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_7.addItem(self.horizontalSpacer_10)
|
||||
|
||||
|
||||
self.verticalLayout_5.addWidget(self.frame_4)
|
||||
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.left_column)
|
||||
|
||||
self.right_column = QFrame(self.frame_2)
|
||||
self.right_column.setObjectName(u"right_column")
|
||||
sizePolicy2.setHeightForWidth(self.right_column.sizePolicy().hasHeightForWidth())
|
||||
self.right_column.setSizePolicy(sizePolicy2)
|
||||
self.right_column.setMinimumSize(QSize(0, 650))
|
||||
self.right_column.setMaximumSize(QSize(700, 650))
|
||||
self.right_column.setFrameShape(QFrame.Shape.NoFrame)
|
||||
self.right_column.setFrameShadow(QFrame.Shadow.Raised)
|
||||
self.verticalLayout_2 = QVBoxLayout(self.right_column)
|
||||
self.verticalLayout_2.setSpacing(0)
|
||||
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
|
||||
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||
self.title_frame = QFrame(self.right_column)
|
||||
self.title_frame.setObjectName(u"title_frame")
|
||||
sizePolicy1.setHeightForWidth(self.title_frame.sizePolicy().hasHeightForWidth())
|
||||
self.title_frame.setSizePolicy(sizePolicy1)
|
||||
self.title_frame.setMinimumSize(QSize(0, 140))
|
||||
self.title_frame.setMaximumSize(QSize(16777215, 180))
|
||||
self.title_frame.setStyleSheet(u"")
|
||||
self.title_frame.setFrameShape(QFrame.Shape.NoFrame)
|
||||
self.title_frame.setFrameShadow(QFrame.Shadow.Raised)
|
||||
self.verticalLayout_3 = QVBoxLayout(self.title_frame)
|
||||
self.verticalLayout_3.setSpacing(0)
|
||||
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
|
||||
self.verticalLayout_3.setContentsMargins(-1, -1, -1, 9)
|
||||
self.maintitle_label = QLabel(self.title_frame)
|
||||
self.maintitle_label.setObjectName(u"maintitle_label")
|
||||
|
||||
self.verticalLayout_3.addWidget(self.maintitle_label, 0, Qt.AlignmentFlag.AlignHCenter)
|
||||
|
||||
self.verticalSpacer = QSpacerItem(20, 10, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)
|
||||
|
||||
self.verticalLayout_3.addItem(self.verticalSpacer)
|
||||
|
||||
self.subtitle_label = QLabel(self.title_frame)
|
||||
self.subtitle_label.setObjectName(u"subtitle_label")
|
||||
self.subtitle_label.setMinimumSize(QSize(0, 0))
|
||||
self.subtitle_label.setTextFormat(Qt.TextFormat.AutoText)
|
||||
self.subtitle_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.verticalLayout_3.addWidget(self.subtitle_label)
|
||||
|
||||
|
||||
self.verticalLayout_2.addWidget(self.title_frame, 0, Qt.AlignmentFlag.AlignHCenter)
|
||||
|
||||
self.btn_frame = QFrame(self.right_column)
|
||||
self.btn_frame.setObjectName(u"btn_frame")
|
||||
sizePolicy1.setHeightForWidth(self.btn_frame.sizePolicy().hasHeightForWidth())
|
||||
self.btn_frame.setSizePolicy(sizePolicy1)
|
||||
self.btn_frame.setMinimumSize(QSize(0, 150))
|
||||
self.btn_frame.setMaximumSize(QSize(16777215, 150))
|
||||
self.btn_frame.setStyleSheet(u"")
|
||||
self.btn_frame.setFrameShape(QFrame.Shape.NoFrame)
|
||||
self.btn_frame.setFrameShadow(QFrame.Shadow.Raised)
|
||||
self.verticalLayout_4 = QVBoxLayout(self.btn_frame)
|
||||
self.verticalLayout_4.setObjectName(u"verticalLayout_4")
|
||||
self.horizontalLayout_3 = QHBoxLayout()
|
||||
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
|
||||
self.horizontalSpacer_4 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_3.addItem(self.horizontalSpacer_4)
|
||||
|
||||
self.connexion_btn = QPushButton(self.btn_frame)
|
||||
self.connexion_btn.setObjectName(u"connexion_btn")
|
||||
self.connexion_btn.setMinimumSize(QSize(250, 50))
|
||||
self.connexion_btn.setMaximumSize(QSize(16777215, 16777215))
|
||||
self.connexion_btn.setStyleSheet(u"")
|
||||
icon3 = QIcon()
|
||||
icon3.addFile(u":/assets/padlock-lock.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.connexion_btn.setIcon(icon3)
|
||||
self.connexion_btn.setIconSize(QSize(32, 32))
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.connexion_btn)
|
||||
|
||||
self.spacer_substitution = QWidget(self.btn_frame)
|
||||
self.spacer_substitution.setObjectName(u"spacer_substitution")
|
||||
self.spacer_substitution.setMinimumSize(QSize(53, 0))
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.spacer_substitution)
|
||||
|
||||
self.staff_btn = QPushButton(self.btn_frame)
|
||||
self.staff_btn.setObjectName(u"staff_btn")
|
||||
self.staff_btn.setMinimumSize(QSize(250, 50))
|
||||
self.staff_btn.setMaximumSize(QSize(16777215, 16777215))
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.staff_btn)
|
||||
|
||||
self.horizontalSpacer_6 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_3.addItem(self.horizontalSpacer_6)
|
||||
|
||||
|
||||
self.verticalLayout_4.addLayout(self.horizontalLayout_3)
|
||||
|
||||
self.horizontalLayout_4 = QHBoxLayout()
|
||||
self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
|
||||
self.horizontalSpacer_7 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_4.addItem(self.horizontalSpacer_7)
|
||||
|
||||
self.discord_btn = QPushButton(self.btn_frame)
|
||||
self.discord_btn.setObjectName(u"discord_btn")
|
||||
self.discord_btn.setMinimumSize(QSize(250, 50))
|
||||
icon4 = QIcon()
|
||||
icon4.addFile(u":/assets/Logo_Discord_2015.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.discord_btn.setIcon(icon4)
|
||||
self.discord_btn.setIconSize(QSize(32, 32))
|
||||
|
||||
self.horizontalLayout_4.addWidget(self.discord_btn)
|
||||
|
||||
self.horizontalSpacer_8 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_4.addItem(self.horizontalSpacer_8)
|
||||
|
||||
self.intranet_btn = QPushButton(self.btn_frame)
|
||||
self.intranet_btn.setObjectName(u"intranet_btn")
|
||||
self.intranet_btn.setMinimumSize(QSize(250, 50))
|
||||
icon5 = QIcon()
|
||||
icon5.addFile(u":/assets/computer-tv.svg", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.intranet_btn.setIcon(icon5)
|
||||
self.intranet_btn.setIconSize(QSize(32, 32))
|
||||
|
||||
self.horizontalLayout_4.addWidget(self.intranet_btn)
|
||||
|
||||
self.horizontalSpacer_9 = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum)
|
||||
|
||||
self.horizontalLayout_4.addItem(self.horizontalSpacer_9)
|
||||
|
||||
|
||||
self.verticalLayout_4.addLayout(self.horizontalLayout_4)
|
||||
|
||||
|
||||
self.verticalLayout_2.addWidget(self.btn_frame)
|
||||
|
||||
self.verticalSpacer_3 = QSpacerItem(20, 20, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)
|
||||
|
||||
self.verticalLayout_2.addItem(self.verticalSpacer_3)
|
||||
|
||||
self.info_frame = QFrame(self.right_column)
|
||||
self.info_frame.setObjectName(u"info_frame")
|
||||
sizePolicy1.setHeightForWidth(self.info_frame.sizePolicy().hasHeightForWidth())
|
||||
self.info_frame.setSizePolicy(sizePolicy1)
|
||||
self.info_frame.setMinimumSize(QSize(0, 310))
|
||||
self.info_frame.setMaximumSize(QSize(16777215, 280))
|
||||
self.info_frame.setStyleSheet(u"")
|
||||
self.info_frame.setFrameShape(QFrame.Shape.StyledPanel)
|
||||
self.info_frame.setFrameShadow(QFrame.Shadow.Raised)
|
||||
self.horizontalLayout_5 = QHBoxLayout(self.info_frame)
|
||||
self.horizontalLayout_5.setObjectName(u"horizontalLayout_5")
|
||||
self.info_text = QTextEdit(self.info_frame)
|
||||
self.info_text.setObjectName(u"info_text")
|
||||
self.info_text.setReadOnly(True)
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.info_text)
|
||||
|
||||
|
||||
self.verticalLayout_2.addWidget(self.info_frame)
|
||||
|
||||
self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
|
||||
|
||||
self.verticalLayout_2.addItem(self.verticalSpacer_2)
|
||||
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.right_column)
|
||||
|
||||
|
||||
self.verticalLayout.addWidget(self.frame_2)
|
||||
|
||||
MainWindow.setCentralWidget(self.main_container)
|
||||
|
||||
self.retranslateUi(MainWindow)
|
||||
|
||||
QMetaObject.connectSlotsByName(MainWindow)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, MainWindow):
|
||||
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
|
||||
self.minimize_btn.setText("")
|
||||
self.close_btn.setText("")
|
||||
self.queue_lbl.setText(QCoreApplication.translate("MainWindow", u"Position en file d'attente: ", None))
|
||||
self.queue_position.setText(QCoreApplication.translate("MainWindow", u"20", None))
|
||||
self.volume_btn.setText("")
|
||||
self.maintitle_label.setText(QCoreApplication.translate("MainWindow", u"LA TANI\u00c8RE", None))
|
||||
self.subtitle_label.setText(QCoreApplication.translate("MainWindow", u"Un espace pour se retrouver", None))
|
||||
self.connexion_btn.setText(QCoreApplication.translate("MainWindow", u" Connexion", None))
|
||||
self.staff_btn.setText(QCoreApplication.translate("MainWindow", u"staff", None))
|
||||
self.discord_btn.setText(QCoreApplication.translate("MainWindow", u" Discord", None))
|
||||
self.intranet_btn.setText(QCoreApplication.translate("MainWindow", u" Intranet", None))
|
||||
# retranslateUi
|
||||
|
||||
885
ui/mainwindow_vertical.ui
Normal file
@@ -0,0 +1,885 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::WindowModality::ApplicationModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1199</width>
|
||||
<height>703</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>1199</width>
|
||||
<height>703</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>1199</width>
|
||||
<height>703</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::ContextMenuPolicy::NoContextMenu</enum>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset>
|
||||
<normaloff>:/assets/Icone.ico</normaloff>:/assets/Icone.ico</iconset>
|
||||
</property>
|
||||
<widget class="QWidget" name="main_container">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>1199</width>
|
||||
<height>703</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>1199</width>
|
||||
<height>703</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="title_bar">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>1199</width>
|
||||
<height>50</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>1199</width>
|
||||
<height>50</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>1006</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="minimize_btn">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>25</width>
|
||||
<height>25</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="close_btn">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>42</width>
|
||||
<height>42</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources.qrc">
|
||||
<normaloff>:/assets/system-shutdown.png</normaloff>:/assets/system-shutdown.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>1199</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>1199</width>
|
||||
<height>658</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="left_column">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>450</width>
|
||||
<height>630</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>450</width>
|
||||
<height>630</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="logo_frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_5">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QLabel" name="queue_lbl">
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Position en file d'attente: </string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="queue_position">
|
||||
<property name="text">
|
||||
<string>20</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>50</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QSlider" name="audio_volume_adjust">
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="invertedAppearance">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="mute_btn">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources.qrc">
|
||||
<normaloff>:/assets/sound-speaker.svg</normaloff>:/assets/sound-speaker.svg</iconset>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_10">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>180</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="right_column">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>650</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>700</width>
|
||||
<height>650</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item alignment="Qt::AlignmentFlag::AlignHCenter">
|
||||
<widget class="QFrame" name="title_frame">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>140</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>180</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item alignment="Qt::AlignmentFlag::AlignHCenter">
|
||||
<widget class="QLabel" name="maintitle_label">
|
||||
<property name="text">
|
||||
<string>LA TANIÈRE</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="subtitle_label">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Un espace pour se retrouver</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::TextFormat::AutoText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="btn_frame">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>150</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<spacer name="verticalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="connexion_btn">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>250</width>
|
||||
<height>50</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string> Connexion</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources.qrc">
|
||||
<normaloff>:/assets/padlock-lock.svg</normaloff>:/assets/padlock-lock.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>15</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="staff_btn">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>250</width>
|
||||
<height>50</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>staff</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources.qrc">
|
||||
<normaloff>:/assets/tools-repair.svg</normaloff>:/assets/tools-repair.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>30</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<item>
|
||||
<widget class="QPushButton" name="discord_btn">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>250</width>
|
||||
<height>50</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string> Discord</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources.qrc">
|
||||
<normaloff>:/assets/discord-icon.svg</normaloff>:/assets/discord-icon.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>15</width>
|
||||
<height>15</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="intranet_btn">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>250</width>
|
||||
<height>50</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string> Intranet</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources.qrc">
|
||||
<normaloff>:/assets/computer-tv.svg</normaloff>:/assets/computer-tv.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>32</width>
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="info_frame">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>310</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>280</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Shape::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Shadow::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QTextEdit" name="info_text">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::TextInteractionFlag::NoTextInteraction</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
1340
ui/mainwindow_vertical_pager.ui
Normal file
74
uv.lock
generated
@@ -1,74 +0,0 @@
|
||||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.14"
|
||||
|
||||
[[package]]
|
||||
name = "myproject"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "pyside6" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [{ name = "pyside6", specifier = ">=6.10.2" }]
|
||||
|
||||
[[package]]
|
||||
name = "pyside6"
|
||||
version = "6.10.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pyside6-addons" },
|
||||
{ name = "pyside6-essentials" },
|
||||
{ name = "shiboken6" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/35/0f/5736889fc850794623692cb369e295a994175e51295fa52134626f486296/pyside6-6.10.2-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:4b084293caa7845d0064aaf6af258e0f7caae03a14a33537d0a552131afddaf0", size = 563185, upload-time = "2026-02-02T08:50:47.161Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/35/d3/ab5cd2fac3d34469c7376e0cd18eec92905dbe44748c70bda7699a2a7206/pyside6-6.10.2-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:1b89ce8558d4b4f35b85bff1db90d680912e4d3ce9e79ff804d6fef1d1a151ef", size = 563357, upload-time = "2026-02-02T08:50:48.919Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ea/8c/55bbd50c138c8dc12edc9f25e9d94760a33e574905468e98dff399094baa/pyside6-6.10.2-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:0439f5e9b10ebe6177981bac9e219096ec970ac6ec215bef055279802ba50601", size = 563357, upload-time = "2026-02-02T08:50:50.077Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/d4/673b8112b4a260377f760be835c4e357163fdaf68a56a1aec59aeb8e584b/pyside6-6.10.2-cp39-abi3-win_amd64.whl", hash = "sha256:032bad6b18a17fcbf4dddd0397f49b07f8aae7f1a45b7e4de7037bf7fd6e0edf", size = 569554, upload-time = "2026-02-02T08:50:51.147Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/14/95/bda648fcccf61fe58cb417284716ae30acdddd44f7d4cbad6eea4ccaa872/pyside6-6.10.2-cp39-abi3-win_arm64.whl", hash = "sha256:65a59ad0bc92525639e3268d590948ce07a80ee97b55e7a9200db41d493cac31", size = 553828, upload-time = "2026-02-02T08:50:52.244Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyside6-addons"
|
||||
version = "6.10.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pyside6-essentials" },
|
||||
{ name = "shiboken6" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/61/06/c283567628ffa2cefc3c72374ad607f1dfc9842a03db65f1347b9ae52bee/pyside6_addons-6.10.2-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:0de7d0c9535e17d5e3b634b61314a1867f3b0f6d35c3d7cdc99efc353192faff", size = 322745605, upload-time = "2026-02-02T08:39:19.929Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a5/69/e1ab8c756fd3984b1fd7b186446227f524f6b561160bfbfdba8874b4709a/pyside6_addons-6.10.2-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:030a851163b51dbf0063be59e9ddb6a9e760bde89a28e461ccc81a224d286eaf", size = 170718434, upload-time = "2026-02-02T08:40:55.989Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/e5/18ba86ba86d1231c486d36f9accfe862ed6eb52ca0b698aeaf6e837a87ca/pyside6_addons-6.10.2-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:fcee0373e3fd7b98f014094e5e37b4a39e4de7c5a47c13f654a7d557d4a426ad", size = 166423836, upload-time = "2026-02-02T08:42:44.918Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/13/503bec9201881968c372cb634069535e80aec2489f3907d676e151a1023f/pyside6_addons-6.10.2-cp39-abi3-win_amd64.whl", hash = "sha256:c20150068525a17494f3b6576c5d61c417cf9a5870659e29f5ebd83cd20a78ea", size = 164712775, upload-time = "2026-02-02T08:43:23.729Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/39/44d6710b4dd18d745077b5fc6ded4ba6f32987a6e49c5834529e50f02155/pyside6_addons-6.10.2-cp39-abi3-win_arm64.whl", hash = "sha256:3d18db739b46946ba7b722d8ad4cc2097135033aa6ea57076e64d591e6a345f3", size = 34041396, upload-time = "2026-02-02T08:43:31.246Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyside6-essentials"
|
||||
version = "6.10.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "shiboken6" },
|
||||
]
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/2e/5f18a77f5e0bd730bacec93a690d0ef3c96a9711d213653eacecbf241b8d/pyside6_essentials-6.10.2-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:1dee2cb9803ff135f881dadeb5c0edcef793d1ec4f8a9140a1348cecb71074e1", size = 105913067, upload-time = "2026-02-02T08:45:37.508Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/20/3a6ca95052e1744b5a3eba164e2dd451d358a3dcaf78179de4b45c8e3f47/pyside6_essentials-6.10.2-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:660aea45bfa36f1e06f799b934c2a7df963bd31abc5083e8bb8a5bfaef45686b", size = 77027153, upload-time = "2026-02-02T08:45:53.09Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/93/a6/6073e4ddc2a5c7b3941606e4bc8bbaadcf0737f57450620b0793041c8d22/pyside6_essentials-6.10.2-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:c2b028e4c6f8047a02c31f373408e23b4eedfd405f56c6aba8d0525c29472835", size = 76114242, upload-time = "2026-02-02T08:46:07.184Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/a8/616bbbd009efd3e17bf9a2db09d90c6764c010565cd2bdea2a240bfd18f7/pyside6_essentials-6.10.2-cp39-abi3-win_amd64.whl", hash = "sha256:0741018c2b6395038cad4c41775cfae3f13a409e87995ac9f7d89e5b1fb6b22a", size = 74546490, upload-time = "2026-02-02T08:46:26.395Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b9/f9/c9757a984c4ffb6d12fab69e966d95dfc862a5d44e12b7900f3a03780b76/pyside6_essentials-6.10.2-cp39-abi3-win_arm64.whl", hash = "sha256:db5f4913648bb6afddb8b347edae151ee2378f12bceb03c8b2515a530a4b38d9", size = 55258626, upload-time = "2026-02-02T08:46:36.788Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shiboken6"
|
||||
version = "6.10.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/38/3912eb08a3b865b5fcdb4bdce8076cacc211986cee587f5cb62e637791af/shiboken6-6.10.2-cp39-abi3-macosx_13_0_universal2.whl", hash = "sha256:3bd4e94e9a3c8c1fa8362fd752d399ef39265d5264e4e37bae61cdaa2a00c8c7", size = 479829, upload-time = "2026-02-02T08:50:22.495Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/88/292e0576489c46624ab419ee284ac5a59ae10e2eb34a58b6abca51dfd290/shiboken6-6.10.2-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ace0790032d9cb0adda644b94ee28d59410180d9773643bb6cf8438c361987ad", size = 273052, upload-time = "2026-02-02T08:50:24.539Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/06/c2/03d44d34e8264e1f25671677fece95b414c70fd85dcc2be8d5e821ee2628/shiboken6-6.10.2-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:f74d3ed1f92658077d0630c39e694eb043aeb1d830a5d275176c45d07147427f", size = 269868, upload-time = "2026-02-02T08:50:25.662Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/71/5d/5ca52c0ef86b3d01572131b6709bd531a080995f7e680720e9424328ce1d/shiboken6-6.10.2-cp39-abi3-win_amd64.whl", hash = "sha256:10f3c8c5e1b8bee779346f21c10dbc14cff068f0b0b4e62420c82a6bf36ac2e7", size = 1222052, upload-time = "2026-02-02T08:50:27.502Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/46/52/421fd378313c89b67ee7d584bf4e9ec088fa1804891b8d74e02b16703457/shiboken6-6.10.2-cp39-abi3-win_arm64.whl", hash = "sha256:20c671645d70835af212ee05df60361d734c5305edb2746e9875c6a31283f963", size = 1784089, upload-time = "2026-02-02T08:50:29.069Z" },
|
||||
]
|
||||